* $Id$
*
* Written by Keith Marshall <keithmarshall@users.sourceforge.net>
- * Copyright (C) 2012, MinGW Project
+ * Copyright (C) 2012, 2013, MinGW.org Project
*
*
* Implementation of the classes and methods required to support the
#include "pkgkeys.h"
#include "pkginfo.h"
#include "pkglist.h"
+#include "pkgproc.h"
#include "pkgtask.h"
#include <windowsx.h>
*/
TextOutW( canvas, bounds->left, bounds->top - offset, linebuf, filled );
}
+ else if( (fold == 0) && (new_width > max_width) )
+ /*
+ * The output line which we've just processed lies outside
+ * the viewport. We note that it's initial (non-breakable)
+ * "word" would require more display width than the viewport
+ * can accommodate, if it were to be moved into the visible
+ * region; thus, this "word" will continue to be presented
+ * to the formatting engine, as the next input "word" to be
+ * processed. This would result in an infinite loop, so we
+ * MUST discard this "word" from the input queue.
+ */
+ curr = (pkgTroffLayoutEngine *)(curr->next);
+
/* Finally, adjust the top boundary of the viewport, to indicate
* where the NEXT output line, if any, is to be positioned, and
* return TRUE, to indicate that an output line was processed.
static int DisplayLicenceURL( const char * );
static int DisplayPackageURL( const char * );
inline void DisplayDescription( pkgXmlNode * );
+ inline void DisplayFilesManifest( pkgXmlNode * );
void ComposeDescription( pkgXmlNode *, pkgXmlNode * );
int FormatRecord( int, const char *, const char * );
inline void FormatText( const char * );
}
}
+void DataSheetMaker::DisplayFilesManifest( pkgXmlNode *ref )
+{
+ /* Helper method to compile the list of files installed by a package,
+ * for display on the "Installed Files" tab of the data sheet panel.
+ */
+ pkgActionItem avail;
+ if( (ref = pkgGetStatus( ref, &avail )) == NULL )
+ {
+ /* This represents a package which is available, but has not been
+ * installed; we simply decline to compile the files list.
+ */
+ FormatRecord( 0, "Package",
+ avail.Selection()->GetPropVal( tarname_key, value_unknown )
+ );
+ bounding_box.top += PARAGRAPH_MARGIN;
+ FormatText(
+ "This package has not been installed; "
+ "the list of installed files is not available for packages "
+ "which have not been installed."
+ );
+ }
+ else
+ { /* This represents a package which has been installed; begin
+ * compilation of the list of installed files.
+ */
+ const char *tarname;
+ FormatRecord( 0, "Package",
+ tarname = ref->GetPropVal( tarname_key, value_unknown )
+ );
+ if( match_if_explicit( ref->ArchiveName(), value_none ) )
+ {
+ /* This is a meta-package; there are no files to list.
+ */
+ bounding_box.top += PARAGRAPH_MARGIN;
+ FormatText(
+ "This meta-package facilitates the installation of a collection "
+ "of other logically related packages; it provides no files, and "
+ "may be safely removed."
+ );
+ }
+ else
+ { /* This is a real package; retrieve the manifest of installed files,
+ * which was created during the installation process.
+ */
+ pkgXmlNode *index;
+ pkgManifest inventory( package_key, tarname );
+ if( (index = inventory.GetRoot()->FindFirstAssociate( manifest_key )) != NULL )
+ {
+ /* We've located a files list within the manifest; process it...
+ */
+ FormatRecord( 0, "This package provides the following files", "" );
+ bounding_box.left += LEFT_MARGIN; bounding_box.top += PARAGRAPH_MARGIN;
+ do { if( (ref = index->FindFirstAssociate( filename_key )) != NULL )
+ /*
+ * We found at least one file name within the list; emit it
+ * to the display, followed by any additional names present.
+ */
+ do { FormatText( ref->GetPropVal( pathname_key, value_unknown ) );
+ } while( (ref = ref->FindNextAssociate( filename_key )) != NULL );
+
+ /* There should be no more than one, but check for, and process
+ * any additional files lists which may be present.
+ */
+ } while( (index = index->FindNextAssociate( manifest_key )) != NULL );
+ }
+ else
+ { /* The manifest appears to be lacking any files list; diagnose.
+ */
+ bounding_box.top += PARAGRAPH_MARGIN;
+ FormatText( "This package appears to provide no files." );
+ }
+ }
+ }
+}
+
static pkgXmlNode *pkgListSelection( HWND package_ref, LVITEM *lookup )
{
/* Helper function, to retrieve the active selection from the
DisplayDescription( pkgListSelection( PackageRef, &lookup ) );
break;
+ case PKG_DATASHEET_INSTALLED_FILES:
+ /* Available only for packages which have been installed,
+ * this comprises the files list content from the manifest
+ * which was created during the installation process.
+ */
+ DisplayFilesManifest( pkgListSelection( PackageRef, &lookup ) );
+ break;
+
default:
/* Handle requests for data sheets for which we have yet
* to provide a compiling routine.
*/
TCITEM tab;
tab.mask = TCIF_TEXT;
- char *TabLegend[] =
+ const char *TabLegend[] =
{ "General", "Description", "Dependencies", "Installed Files", "Versions",
/* ...with a NULL sentinel marking the preceding label as
{
/* This loop assumes responsibility for actual tab creation...
*/
- tab.pszText = TabLegend[i];
+ tab.pszText = (char *)(TabLegend[i]);
if( TabCtrl_InsertItem( PackageTabControl, i, &tab ) == -1 )
{
/* ...bailing out, and deleting the container window,
}
}
+void AppWindowMaker::UpdateDataSheet( void )
+{
+ /* Helper method, called when we wish to update the data sheet
+ * panel, to match the current list view and tab selection.
+ */
+ DataSheet->DisplayData( PackageTabControl, PackageListView );
+}
+
long AppWindowMaker::OnNotify( WPARAM client_id, LPARAM data )
{
/* Handler for notifiable events to be processed in the context
case ID_PACKAGE_LISTVIEW:
if( ((NMHDR *)(data))->code == NM_RCLICK )
{
- /* A right button mouse click within the package list view
- * selects the package under the cursor, and offers a pop-up
- * menu of actions which may be performed on it.
+ /* A right mouse button click within the package list view
+ * selects the package under the cursor, refreshing the tab
+ * pane to display its associated data sheet, and offers a
+ * pop-up menu of actions which may be performed on it.
*/
+ UpdateDataSheet();
SelectPackageAction( LVHT_ONITEMICON | LVHT_ONITEMLABEL );
break;
}
/* ...each of which may require the data sheet content
* to be updated, (to reflect a changed selection).
*/
- DataSheet->DisplayData( PackageTabControl, PackageListView );
+ UpdateDataSheet();
/* Additionally, for a left click on the package status
* icon within the list view, we present a pop-up menu
SelectPackageAction( LVHT_ONITEMICON );
}
break;
+
+ /* We also need to consider notifications from the tree view...
+ */
+ case ID_PACKAGE_TREEVIEW:
+ if( ((NMHDR *)(data))->code == TVN_SELCHANGED )
+ {
+ /* ...from which we are interested only in notifications
+ * that the user has changed the package group selection.
+ *
+ * First, we ensure that any children of the selected
+ * package group are made visible.
+ */
+ TreeView_Expand( PackageTreeView,
+ ((NMTREEVIEW *)(data))->itemNew.hItem, TVE_EXPAND
+ );
+
+ /* We then clear out the previous content of the list view
+ * pane, and reconstruct it with new content, as determined
+ * by the new package group selection...
+ */
+ ClearPackageList();
+ UpdatePackageList();
+
+ /* ...and reapply any scheduled action markers, which may
+ * be applicable.
+ */
+ MarkSchedule( pkgData->Schedule() );
+
+ /* Finally, provided the previous selection is not an
+ * ancestor of the current, we may collapse any visible
+ * subtree descending from the previous.
+ *
+ * FIXME: We may wish to avoid collapsing any subtree
+ * which was designated as "expanded", in the original
+ * group hierarchy specification. We may also wish to
+ * provide a user option, to disable this feature.
+ */
+ bool may_fold = true;
+ HTREEITEM prev = ((NMTREEVIEW *)(data))->itemNew.hItem;
+ while( may_fold && (prev != NULL) )
+ { if( prev == ((NMTREEVIEW *)(data))->itemOld.hItem )
+ /*
+ * Previous selection IS an ancestor of current;
+ * we must not collapse it.
+ */
+ may_fold = false;
+
+ else
+ /* Continue tracing ancestry, back to the root.
+ */
+ prev = TreeView_GetParent( PackageTreeView, prev );
+ }
+ if( may_fold )
+ /*
+ * Previous selection may be collapsed; do so.
+ */
+ TreeView_Expand( PackageTreeView,
+ ((NMTREEVIEW *)(data))->itemOld.hItem, TVE_COLLAPSE
+ );
+ }
}
/* Otherwise, this return causes any other notifiable events
* to be simply ignored, (as they were by the original stub).
int action;
if( (action = item->flags & ACTION_MASK) != 0 )
{
- /* ...and, when one is found...
+ /* ...and, when one is found, (noting that ACTION_UPGRADE may
+ * also be considered as a special case of ACTION_INSTALL)...
*/
- if( action == classified )
+ if( (action == classified)
+ || ((action == ACTION_UPGRADE) && (classified == ACTION_INSTALL)) )
{
/* ...and it matches the classification in which
* we are interested, then we retrieve the tarname
++count;
}
}
- else if( classified == 0 )
+ else if( (classified == 0)
+ /*
+ * ...otherwise, when we aren't interested in any particular
+ * class of action regardless of classification...
+ */
+ || ((classified == ACTION_UNSUCCESSFUL) && ((flags & classified) != 0)) )
/*
- * ...otherwise, when we aren't interested in any
- * particular class of action, just count all those
- * which are found, regardless of classification.
+ * ...or when we are checking for unsuccessful actions, we
+ * count all those which are found, either unclassified, or
+ * marked as unsuccessful, respectively.
*/
++count;
}
* option for the termination request, so that the user
* has an opportunity to complete such actions.
*/
- if( (pkgData->Schedule()->EnumeratePendingActions() > 0)
- && (MessageBox( AppWindow,
- "You have marked changes which have not been applied;\n"
- "these will be lost, if you quit without applying them.\n\n"
- "Are you sure you want to discard these marked changes?",
- "Discard Marked Changes?", MB_YESNO | MB_ICONWARNING
- ) == IDNO)
- ) return 0;
- return -1;
+ return ConfirmActionRequest( "quit" ) ? -1 : 0;
}
/* $RCSfile$: end of file */