Skip to content

Commit 02c29c0

Browse files
committedJun 7, 2013
[Plugin Manager] Better sorting by status, minor gui fixes and improvements
1 parent 8a85bcb commit 02c29c0

File tree

7 files changed

+231
-88
lines changed

7 files changed

+231
-88
lines changed
 

‎src/app/pluginmanager/qgsapppluginmanagerinterface.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ QgsAppPluginManagerInterface::~QgsAppPluginManagerInterface()
3232
//! show the Plugin Manager window and optionally open tab tabIndex
3333
void QgsAppPluginManagerInterface::showPluginManager( int tabIndex )
3434
{
35-
mPluginManager->getCppPluginDescriptions();
35+
mPluginManager->getCppPluginsMetadata();
3636
mPluginManager->reloadModelData();
3737

3838
//! switch to tab, if specified ( -1 means not specified )

‎src/app/pluginmanager/qgspluginmanager.cpp

Lines changed: 166 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ const QString seenPluginGroup = "/Qgis/plugin-seen";
6060
QgsPluginManager::QgsPluginManager( QWidget * parent, Qt::WFlags fl )
6161
: QgsOptionsDialogBase( "PluginManager", parent, fl )
6262
{
63+
// initialize pointer
64+
mPythonUtils = NULL;
65+
6366
setupUi( this );
6467

6568
// QgsOptionsDialogBase handles saving/restoring of geometry, splitter and current tab states,
@@ -72,63 +75,92 @@ QgsPluginManager::QgsPluginManager( QWidget * parent, Qt::WFlags fl )
7275
mModelProxy = new QgsPluginSortFilterProxyModel( this );
7376
mModelProxy->setSourceModel( mModelPlugins );
7477
mModelProxy->setSortCaseSensitivity( Qt::CaseInsensitive );
78+
mModelProxy->setSortRole( Qt::DisplayRole );
79+
mModelProxy->setDynamicSortFilter( true );
7580
vwPlugins->setModel( mModelProxy );
7681
vwPlugins->setFocus();
7782

78-
// context menu
83+
// Preset widgets
84+
QString wellcomeMsg = tr( "To enable or disable plugin, click its checkbox or doubleclick its name..." );
85+
tbDetails->setHtml( wellcomeMsg );
86+
leFilter->setFocus( Qt::MouseFocusReason );
87+
rbFilterNames->setChecked( true );
88+
89+
// Don't restore the last used tab from QSettings
90+
mOptionsListWidget->setCurrentRow( 0 );
91+
92+
// Connect other signals
93+
connect( mOptionsListWidget, SIGNAL( currentRowChanged( int ) ), this, SLOT( setCurrentTab( int ) ) );
94+
connect( vwPlugins->selectionModel(), SIGNAL( currentChanged( const QModelIndex &, const QModelIndex & ) ), this, SLOT( currentPluginChanged( const QModelIndex & ) ) );
95+
connect( mModelPlugins, SIGNAL( itemChanged( QStandardItem * ) ), this, SLOT( pluginItemChanged( QStandardItem * ) ) );
96+
97+
// Force setting the status filter (if the active tab was 0, the setCurrentRow( 0 ) above doesn't take any action)
98+
setCurrentTab( 0 );
99+
100+
// Hide widgets only suitable with Python support enabled (they will be uncovered back in setPythonUtils)
101+
rbFilterTags->hide();
102+
rbFilterAuthors->hide();
103+
buttonUpgradeAll->hide();
104+
buttonInstall->hide();
105+
buttonUninstall->hide();
106+
mOptionsListWidget->item( 5 )->setHidden( true );
107+
}
108+
109+
110+
111+
QgsPluginManager::~QgsPluginManager()
112+
{
113+
delete mModelProxy;
114+
delete mModelPlugins;
115+
}
116+
117+
118+
119+
void QgsPluginManager::setPythonUtils( QgsPythonUtils* pythonUtils )
120+
{
121+
mPythonUtils = pythonUtils;
122+
123+
// Now enable Python support:
124+
// Show and preset widgets only suitable when Python support active
125+
rbFilterTags->show();
126+
rbFilterAuthors->show();
127+
buttonUpgradeAll->show();
128+
buttonInstall->show();
129+
buttonUninstall->show();
130+
mOptionsListWidget->item( 5 )->setHidden( false );
131+
buttonRefreshRepos->setEnabled( false );
132+
buttonEditRep->setEnabled( false );
133+
buttonDeleteRep->setEnabled( false );
134+
135+
// Add context menu to the plugins list view
79136
QAction* actionSortByName = new QAction( tr( "sort by name" ), vwPlugins );
80137
QAction* actionSortByDownloads = new QAction( tr( "sort by downloads" ), vwPlugins );
81138
QAction* actionSortByVote = new QAction( tr( "sort by vote" ), vwPlugins );
82139
QAction* actionSortByStatus = new QAction( tr( "sort by status" ), vwPlugins );
83-
QAction* actionSortByRepository = new QAction( tr( "sort by repository" ), vwPlugins );
84140
actionSortByName->setCheckable( true );
85141
actionSortByDownloads->setCheckable( true );
86142
actionSortByVote->setCheckable( true );
87143
actionSortByStatus->setCheckable( true );
88-
actionSortByRepository->setCheckable( true );
89144
QActionGroup * group = new QActionGroup( vwPlugins );
90145
actionSortByName->setActionGroup( group );
91146
actionSortByDownloads->setActionGroup( group );
92147
actionSortByVote->setActionGroup( group );
93148
actionSortByStatus->setActionGroup( group );
94-
actionSortByRepository->setActionGroup( group );
95149
actionSortByName->setChecked( true );
96150
vwPlugins->addAction( actionSortByName );
97151
vwPlugins->addAction( actionSortByDownloads );
98152
vwPlugins->addAction( actionSortByVote );
99153
vwPlugins->addAction( actionSortByStatus );
100-
vwPlugins->addAction( actionSortByRepository );
101154
vwPlugins->setContextMenuPolicy( Qt::ActionsContextMenu );
102155
connect( actionSortByName, SIGNAL( triggered( ) ), mModelProxy, SLOT( sortPluginsByName( ) ) );
103156
connect( actionSortByDownloads, SIGNAL( triggered( ) ), mModelProxy, SLOT( sortPluginsByDownloads( ) ) );
104157
connect( actionSortByVote, SIGNAL( triggered( ) ), mModelProxy, SLOT( sortPluginsByVote( ) ) );
105158
connect( actionSortByStatus, SIGNAL( triggered( ) ), mModelProxy, SLOT( sortPluginsByStatus( ) ) );
106-
connect( actionSortByRepository, SIGNAL( triggered( ) ), mModelProxy, SLOT( sortPluginsByRepository( ) ) );
107-
mModelProxy->setSortRole( Qt::DisplayRole );
108-
109-
// Connect other signals
110-
connect( mOptionsListWidget, SIGNAL( currentRowChanged( int ) ), this, SLOT( setCurrentTab( int ) ) );
111-
connect( vwPlugins->selectionModel(), SIGNAL( currentChanged( const QModelIndex &, const QModelIndex & ) ), this, SLOT( currentPluginChanged( const QModelIndex & ) ) );
112-
connect( mModelPlugins, SIGNAL( itemChanged( QStandardItem * ) ), this, SLOT( pluginItemChanged( QStandardItem * ) ) );
113-
114-
QString wellcomeMsg = tr( "To enable or disable plugin, click its checkbox or doubleclick its name..." );
115-
tbDetails->setHtml( wellcomeMsg );
116-
leFilter->setFocus( Qt::MouseFocusReason );
117-
rbFilterNames->setChecked( true );
118-
buttonRefreshRepos->setEnabled( false );
119-
buttonEditRep->setEnabled( false );
120-
buttonDeleteRep->setEnabled( false );
121-
122-
// Don't restore the last used tab from QSettings
123-
mOptionsListWidget->setCurrentRow( 0 );
124-
125-
// Force setting the status filter (if the active tab was 0, the previous line doesn't take any action)
126-
setCurrentTab( 0 );
127159

128160
// Initialize list of allowed checking intervals
129-
checkingOnStartIntervals << 0 << 1 << 3 << 7 << 14 << 30 ;
161+
mCheckingOnStartIntervals << 0 << 1 << 3 << 7 << 14 << 30 ;
130162

131-
// Initialize the "Setting" tab widgets
163+
// Initialize the "Settings" tab widgets
132164
QSettings settings;
133165
if ( settings.value( settingsGroup + "/checkOnStart", false ).toBool() )
134166
{
@@ -141,27 +173,12 @@ QgsPluginManager::QgsPluginManager( QWidget * parent, Qt::WFlags fl )
141173
}
142174

143175
int interval = settings.value( settingsGroup + "/checkOnStartInterval", "" ).toInt( );
144-
int indx = checkingOnStartIntervals.indexOf( interval ); // if none found, just use -1 index.
176+
int indx = mCheckingOnStartIntervals.indexOf( interval ); // if none found, just use -1 index.
145177
comboInterval->setCurrentIndex( indx );
146178
}
147179

148180

149181

150-
QgsPluginManager::~QgsPluginManager()
151-
{
152-
delete mModelProxy;
153-
delete mModelPlugins;
154-
}
155-
156-
157-
158-
void QgsPluginManager::setPythonUtils( QgsPythonUtils* pythonUtils )
159-
{
160-
mPythonUtils = pythonUtils;
161-
}
162-
163-
164-
165182
void QgsPluginManager::loadPlugin( QString id )
166183
{
167184
QMap<QString, QString>* plugin = pluginMetadata( id );
@@ -220,7 +237,7 @@ void QgsPluginManager::unloadPlugin( QString id )
220237

221238

222239

223-
void QgsPluginManager::getCppPluginDescriptions()
240+
void QgsPluginManager::getCppPluginsMetadata()
224241
{
225242
QString sharedLibExtension;
226243
#if defined(WIN32) || defined(__CYGWIN__)
@@ -371,6 +388,7 @@ void QgsPluginManager::getCppPluginDescriptions()
371388
metadata["pythonic"] = "false";
372389
metadata["installed"] = "true";
373390
metadata["readonly"] = "true";
391+
metadata["status"] = "orphan";
374392
metadata["experimental"] = ( pExperimental ? pExperimental() : QString() );
375393
mPlugins.insert( baseName, metadata );
376394

@@ -381,6 +399,22 @@ void QgsPluginManager::getCppPluginDescriptions()
381399

382400

383401

402+
QStandardItem * QgsPluginManager::createSpacerItem( QString text, QString value )
403+
{
404+
QStandardItem * mySpacerltem = new QStandardItem( text );
405+
mySpacerltem->setData( value, PLUGIN_STATUS_ROLE );
406+
mySpacerltem->setData( "status", SPACER_ROLE );
407+
mySpacerltem->setEnabled( false );
408+
mySpacerltem->setEditable( false );
409+
QFont font = mySpacerltem->font();
410+
font.setBold( true );
411+
mySpacerltem->setFont( font );
412+
mySpacerltem->setTextAlignment( Qt::AlignHCenter );
413+
return mySpacerltem;
414+
}
415+
416+
417+
384418
void QgsPluginManager::reloadModelData()
385419
{
386420
mModelPlugins->clear();
@@ -389,7 +423,6 @@ void QgsPluginManager::reloadModelData()
389423
it != mPlugins.end();
390424
it++ )
391425
{
392-
393426
if ( ! it->value( "id" ).isEmpty() )
394427
{
395428
QString baseName = it->value( "id" );
@@ -464,11 +497,22 @@ void QgsPluginManager::reloadModelData()
464497
}
465498
}
466499

500+
// Add spacers for sort by status
501+
if ( mPythonUtils && mPythonUtils->isEnabled() )
502+
{
503+
// TODO: implement better sort method instead of these dummy -Z statuses
504+
mModelPlugins->appendRow( createSpacerItem( tr( "Reinstallable plugins", "category: plugins that are installed and available" ) , "installedZ" ) );
505+
if ( hasUpgradeablePlugins() ) mModelPlugins->appendRow( createSpacerItem( tr( "Upgradeable plugins", "category: plugins that are installed and there is newer version available" ), "upgradeableZ") );
506+
mModelPlugins->appendRow( createSpacerItem( tr( "Only locally available", "category: plugins that are only locally available" ), "orphanZ" ) );
507+
if ( hasNewerPlugins() ) mModelPlugins->appendRow( createSpacerItem( tr( "Newer locally", "category: plugins installed and availabie; installed version is newer" ), "newerZ" ) );
508+
}
509+
467510
updateTabTitle();
468511

469512
buttonUpgradeAll->setEnabled( hasUpgradeablePlugins() );
470513

471514
// Disable tabs that are empty because of no suitable plugins in the model.
515+
mOptionsListWidget->item( 1 )->setHidden( ! hasAvailablePlugins() );
472516
mOptionsListWidget->item( 2 )->setHidden( ! hasUpgradeablePlugins() );
473517
mOptionsListWidget->item( 3 )->setHidden( ! hasNewPlugins() );
474518
mOptionsListWidget->item( 4 )->setHidden( ! hasInvalidPlugins() );
@@ -525,11 +569,11 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
525569
QString errorMsg;
526570
if ( metadata->value( "error" ) == "incompatible" )
527571
{
528-
errorMsg = QString( "<b>%1</b><br/><%2> %3" ).arg( tr( "This plugin is incompatible with this version of QGIS" ) ).arg( tr( "Compatible versions:" ) ).arg( metadata->value( "error_details" ) );
572+
errorMsg = QString( "<b>%1</b><br/>%2" ).arg( tr( "This plugin is incompatible with this version of QGIS" ) ).arg( tr( "Plugin designed for QGIS %1", "compatible QGIS version(s)" ).arg( metadata->value( "error_details" ) ) );
529573
}
530574
else if ( metadata->value( "error" ) == "dependent" )
531575
{
532-
errorMsg = QString( "<b>%1</b>:<br/>%2" ).arg( tr( "This plugin requires a missing module" ) ).arg( metadata->value( "error_details" ) );
576+
errorMsg = QString( "<b>%1:</b><br/>%2" ).arg( tr( "This plugin requires a missing module" ) ).arg( metadata->value( "error_details" ) );
533577
}
534578
else
535579
{
@@ -665,22 +709,20 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
665709
{
666710
buttonInstall->setText( tr( "Downgrade plugin" ) );
667711
}
668-
else if ( metadata->value( "status" ) == "installed" )
669-
{
670-
buttonInstall->setText( tr( "Reinstall plugin" ) );
671-
}
672712
else if ( metadata->value( "status" ) == "not installed" || metadata->value( "status" ) == "new" )
673713
{
674714
buttonInstall->setText( tr( "Install plugin" ) );
675715
}
676716
else
677717
{
678-
buttonInstall->setText( tr( "Install/upgrade plugin" ) );
718+
// Default (will be grayed out if not available for reinstallation)
719+
buttonInstall->setText( tr( "Reinstall plugin" ) );
679720
}
680721

681722
// Enable/disable buttons
682723
buttonInstall->setEnabled( metadata->value( "pythonic" ).toUpper() == "TRUE" && metadata->value( "status" ) != "orphan" );
683724
buttonUninstall->setEnabled( metadata->value( "pythonic" ).toUpper() == "TRUE" && metadata->value( "status" ) != "readonly" && metadata->value( "status" ) != "not installed" && metadata->value( "status" ) != "new" );
725+
buttonUninstall->setHidden( metadata->value( "status" ) == "not installed" || metadata->value( "status" ) == "new" );
684726

685727
// Store the id of the currently displayed plugin
686728
mCurrentlyDisplayedPlugin = metadata->value( "id" );
@@ -743,6 +785,16 @@ void QgsPluginManager::clearRepositoryList()
743785
//! Add repository to the repository listWidget
744786
void QgsPluginManager::addToRepositoryList( QMap<QString, QString> repository )
745787
{
788+
// If the item is second on the tree, add a context menu
789+
if ( buttonRefreshRepos->isEnabled() && treeRepositories->actions().count() < 1 )
790+
{
791+
QAction* actionEnableThisRepositoryOnly = new QAction( tr( "Enable selected repository only" ), treeRepositories );
792+
actionEnableThisRepositoryOnly->setCheckable( true );
793+
treeRepositories->addAction( actionEnableThisRepositoryOnly );
794+
treeRepositories->setContextMenuPolicy( Qt::ActionsContextMenu );
795+
connect( actionEnableThisRepositoryOnly, SIGNAL( toggled( bool ) ), this, SLOT( enableSelectedRepositoryOnly( bool ) ) );
796+
}
797+
746798
QString key = repository.value( "name" );
747799
if ( ! key.isEmpty() )
748800
{
@@ -795,14 +847,16 @@ void QgsPluginManager::addToRepositoryList( QMap<QString, QString> repository )
795847
// SLOTS ///////////////////////////////////////////////////////////////////
796848

797849

798-
799850
// "Close" button clicked
800851
void QgsPluginManager::reject()
801852
{
802-
QSettings settings;
803-
settings.setValue( settingsGroup + "/checkOnStart", QVariant( ckbCheckUpdates->isChecked() ) );
804-
settings.setValue( settingsGroup + "/checkOnStartInterval", QVariant( checkingOnStartIntervals.value( comboInterval->currentIndex() ) ) );
805-
QgsPythonRunner::run( "pyplugin_installer.instance().onManagerClose()" );
853+
if ( mPythonUtils && mPythonUtils->isEnabled() )
854+
{
855+
QSettings settings;
856+
settings.setValue( settingsGroup + "/checkOnStart", QVariant( ckbCheckUpdates->isChecked() ) );
857+
settings.setValue( settingsGroup + "/checkOnStartInterval", QVariant( mCheckingOnStartIntervals.value( comboInterval->currentIndex() ) ) );
858+
QgsPythonRunner::run( "pyplugin_installer.instance().onManagerClose()" );
859+
}
806860
done( 1 );
807861
}
808862

@@ -824,8 +878,8 @@ void QgsPluginManager::setCurrentTab( int idx )
824878
switch ( idx )
825879
{
826880
case 0:
827-
// installed
828-
acceptedStatuses << "installed" << "orphan" << "newer" << "upgradeable" << "";
881+
// installed (statuses ends with Z are for spacers to always sort properly)
882+
acceptedStatuses << "installed" << "orphan" << "newer" << "upgradeable" << "installedZ" << "upgradeableZ" << "orphanZ" << "newerZZ" << "" ;
829883
break;
830884
case 1:
831885
// not installed (get more)
@@ -996,6 +1050,26 @@ void QgsPluginManager::on_treeRepositories_doubleClicked( QModelIndex )
9961050

9971051

9981052

1053+
void QgsPluginManager::enableSelectedRepositoryOnly( bool checked )
1054+
{
1055+
if ( ! checked ) {
1056+
QgsDebugMsg( "Enabling all repositories back");
1057+
QgsPythonRunner::run( QString( "pyplugin_installer.instance().enableThisRepositoryOnly()" ) );
1058+
return;
1059+
}
1060+
1061+
QTreeWidgetItem * current = treeRepositories->currentItem();
1062+
if ( current )
1063+
{
1064+
QString key = current->text( 1 );
1065+
key = key.replace( "\'", "\\\'" ).replace( "\"", "\\\"" );
1066+
QgsDebugMsg( "Disabling all repositories but selected: " + key );
1067+
QgsPythonRunner::run( QString( "pyplugin_installer.instance().enableThisRepositoryOnly('%1')" ).arg( key ) );
1068+
}
1069+
}
1070+
1071+
1072+
9991073
void QgsPluginManager::on_buttonRefreshRepos_clicked( )
10001074
{
10011075
QgsDebugMsg( "Refreshing repositories..." );
@@ -1053,7 +1127,6 @@ void QgsPluginManager::on_ckbExperimental_toggled( bool state )
10531127
// PRIVATE METHODS ///////////////////////////////////////////////////////////////////
10541128

10551129

1056-
10571130
bool QgsPluginManager::isPluginLoaded( QString key )
10581131
{
10591132
QMap<QString, QString>* plugin = pluginMetadata( key );
@@ -1083,6 +1156,21 @@ bool QgsPluginManager::isPluginLoaded( QString key )
10831156
}
10841157

10851158

1159+
bool QgsPluginManager::hasAvailablePlugins( )
1160+
{
1161+
for ( QMap<QString, QMap<QString, QString> >::iterator it = mPlugins.begin();
1162+
it != mPlugins.end();
1163+
it++ )
1164+
{
1165+
if ( it->value( "status" ) == "not installed" || it->value( "status" ) == "new" )
1166+
{
1167+
return true;
1168+
}
1169+
}
1170+
1171+
return false;
1172+
}
1173+
10861174

10871175
bool QgsPluginManager::hasUpgradeablePlugins( )
10881176
{
@@ -1118,6 +1206,23 @@ bool QgsPluginManager::hasNewPlugins( )
11181206

11191207

11201208

1209+
bool QgsPluginManager::hasNewerPlugins( )
1210+
{
1211+
for ( QMap<QString, QMap<QString, QString> >::iterator it = mPlugins.begin();
1212+
it != mPlugins.end();
1213+
it++ )
1214+
{
1215+
if ( it->value( "status" ) == "newer" )
1216+
{
1217+
return true;
1218+
}
1219+
}
1220+
1221+
return false;
1222+
}
1223+
1224+
1225+
11211226
bool QgsPluginManager::hasInvalidPlugins( )
11221227
{
11231228
for ( QMap<QString, QMap<QString, QString> >::iterator it = mPlugins.begin();

‎src/app/pluginmanager/qgspluginmanager.h

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class QgsPluginManager : public QgsOptionsDialogBase, private Ui::QgsPluginManag
4444
//! Destructor
4545
~QgsPluginManager();
4646

47-
//! Save pointer to python utils
47+
//! Save pointer to python utils and enable Python support
4848
void setPythonUtils( QgsPythonUtils* pythonUtils );
4949

5050
//! Load selected plugin
@@ -54,7 +54,10 @@ class QgsPluginManager : public QgsOptionsDialogBase, private Ui::QgsPluginManag
5454
void unloadPlugin( QString id );
5555

5656
//! Get metadata of C++ plugins
57-
void getCppPluginDescriptions();
57+
void getCppPluginsMetadata();
58+
59+
//! Create new spacer item for sorting by status in the plugin list view
60+
QStandardItem * createSpacerItem( QString text, QString value );
5861

5962
//! Repopulate the plugin list model
6063
void reloadModelData();
@@ -153,17 +156,26 @@ class QgsPluginManager : public QgsOptionsDialogBase, private Ui::QgsPluginManag
153156
//! Reimplement QgsOptionsDialogBase method to prevent modifying the tab list by signals from the stacked widget
154157
void optionsStackedWidget_CurrentChanged( int indx ) { Q_UNUSED( indx ) }
155158

159+
//! Enable selected repository only
160+
void enableSelectedRepositoryOnly( bool checked );
161+
156162
private:
157163
//! Return true if given plugin is currently present in QgsPluginRegistry
158164
bool isPluginLoaded( QString key );
159165

160-
//! Return true if there are upgradeable plugins in the registry
166+
//! Return true if there are plugins available for download in the metadata registry
167+
bool hasAvailablePlugins( );
168+
169+
//! Return true if there are upgradeable plugins in metadata the registry
161170
bool hasUpgradeablePlugins( );
162171

163-
//! Return true if there are new plugins in the registry
172+
//! Return true if there are new plugins in the metadata registry
164173
bool hasNewPlugins( );
165174

166-
//! Return true if there are invalid plugins in the registry
175+
//! Return true if there are plugins in the metadata registry that are newer installed than available
176+
bool hasNewerPlugins( );
177+
178+
//! Return true if there are invalid plugins in the metadata registry
167179
bool hasInvalidPlugins( );
168180

169181
QStandardItemModel *mModelPlugins;
@@ -176,7 +188,7 @@ class QgsPluginManager : public QgsOptionsDialogBase, private Ui::QgsPluginManag
176188

177189
QString mCurrentlyDisplayedPlugin;
178190

179-
QList<int> checkingOnStartIntervals;
191+
QList<int> mCheckingOnStartIntervals;
180192
};
181193

182194
#endif

‎src/app/pluginmanager/qgspluginsortfilterproxymodel.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
***************************************************************************/
1616

1717
#include "qgspluginsortfilterproxymodel.h"
18-
#include "qgslogger.h"
18+
19+
1920

2021
QgsPluginSortFilterProxyModel::QgsPluginSortFilterProxyModel( QObject *parent ) : QSortFilterProxyModel( parent )
2122
{
@@ -27,6 +28,13 @@ bool QgsPluginSortFilterProxyModel::filterAcceptsRow( int sourceRow, const QMode
2728
{
2829
QModelIndex inx = sourceModel()->index( sourceRow, 0, sourceParent );
2930

31+
if ( ! sourceModel()->data( inx, SPACER_ROLE ).toString().isEmpty() )
32+
{
33+
// it's a status spacer.
34+
// TODO: the condition below is only suitable for status spacers
35+
return ( filterByStatus( inx ) && mAcceptedStatuses.count()>1 && sourceModel()->data( inx, SPACER_ROLE ).toString() == mAcceptedSpacers );
36+
}
37+
3038
return ( filterByStatus( inx ) && sourceModel()->data( inx, filterRole() ).toString().contains( filterRegExp() ) );
3139
}
3240

@@ -40,6 +48,14 @@ void QgsPluginSortFilterProxyModel::setAcceptedStatuses( QStringList statuses )
4048

4149

4250

51+
void QgsPluginSortFilterProxyModel::setAcceptedSpacers( QString spacers )
52+
{
53+
mAcceptedSpacers = spacers;
54+
invalidateFilter();
55+
}
56+
57+
58+
4359
bool QgsPluginSortFilterProxyModel::filterByStatus( QModelIndex &index ) const
4460
{
4561
if ( mAcceptedStatuses.contains( "invalid" )
@@ -49,9 +65,11 @@ bool QgsPluginSortFilterProxyModel::filterByStatus( QModelIndex &index ) const
4965
return false;
5066
}
5167

68+
QString status = sourceModel()->data( index, PLUGIN_STATUS_ROLE ).toString();
69+
if ( status.endsWith( "Z" ) ) status.chop( 1 );
5270
if ( ! mAcceptedStatuses.isEmpty()
5371
&& ! mAcceptedStatuses.contains( "invalid" )
54-
&& ! mAcceptedStatuses.contains( sourceModel()->data( index, PLUGIN_STATUS_ROLE ).toString() ) )
72+
&& ! mAcceptedStatuses.contains( status ) )
5573
{
5674
// Don't accept if the status doesn't match
5775
return false;
@@ -81,6 +99,7 @@ int QgsPluginSortFilterProxyModel::countWithCurrentStatus( )
8199

82100
void QgsPluginSortFilterProxyModel::sortPluginsByName( )
83101
{
102+
setAcceptedSpacers();
84103
sort( 0, Qt::AscendingOrder );
85104
setSortRole( Qt::DisplayRole );
86105
}
@@ -89,6 +108,7 @@ void QgsPluginSortFilterProxyModel::sortPluginsByName( )
89108

90109
void QgsPluginSortFilterProxyModel::sortPluginsByDownloads( )
91110
{
111+
setAcceptedSpacers();
92112
sort( 0, Qt::DescendingOrder );
93113
setSortRole( PLUGIN_DOWNLOADS_ROLE );
94114
}
@@ -97,6 +117,7 @@ void QgsPluginSortFilterProxyModel::sortPluginsByDownloads( )
97117

98118
void QgsPluginSortFilterProxyModel::sortPluginsByVote( )
99119
{
120+
setAcceptedSpacers();
100121
sort( 0, Qt::DescendingOrder );
101122
setSortRole( PLUGIN_VOTE_ROLE );
102123
}
@@ -105,14 +126,7 @@ void QgsPluginSortFilterProxyModel::sortPluginsByVote( )
105126

106127
void QgsPluginSortFilterProxyModel::sortPluginsByStatus( )
107128
{
129+
setAcceptedSpacers( "status" );
108130
sort( 0, Qt::DescendingOrder );
109131
setSortRole( PLUGIN_STATUS_ROLE );
110132
}
111-
112-
113-
114-
void QgsPluginSortFilterProxyModel::sortPluginsByRepository( )
115-
{
116-
sort( 0, Qt::DescendingOrder );
117-
setSortRole( PLUGIN_REPOSITORY_ROLE );
118-
}

‎src/app/pluginmanager/qgspluginsortfilterproxymodel.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include <QSortFilterProxyModel>
2121
#include <QStringList>
22+
#include <QString>
2223

2324
const int PLUGIN_BASE_NAME_ROLE = Qt::UserRole + 1;
2425
const int PLUGIN_DESCRIPTION_ROLE = Qt::UserRole + 2; // for filtering
@@ -29,6 +30,8 @@ const int PLUGIN_STATUS_ROLE = Qt::UserRole + 6; // for filtering and sort
2930
const int PLUGIN_DOWNLOADS_ROLE = Qt::UserRole + 7; // for sorting
3031
const int PLUGIN_VOTE_ROLE = Qt::UserRole + 8; // for sorting
3132
const int PLUGIN_REPOSITORY_ROLE = Qt::UserRole + 9; // for sorting
33+
const int SPACER_ROLE = Qt::UserRole + 20; // for sorting
34+
3235

3336

3437
/*!
@@ -44,6 +47,9 @@ class QgsPluginSortFilterProxyModel : public QSortFilterProxyModel
4447
//! (Re)configire the status filter
4548
void setAcceptedStatuses( QStringList statuses );
4649

50+
//! (Re)configire the spacer filter
51+
void setAcceptedSpacers( QString spacers = "" );
52+
4753
//! Return number of item with status filter matching (no other filters are considered)
4854
int countWithCurrentStatus( );
4955

@@ -52,7 +58,6 @@ class QgsPluginSortFilterProxyModel : public QSortFilterProxyModel
5258
void sortPluginsByDownloads( );
5359
void sortPluginsByVote( );
5460
void sortPluginsByStatus( );
55-
void sortPluginsByRepository( );
5661

5762
protected:
5863
//! Filter by status: this method is used in both filterAcceptsRow and countWithCurrentStatus.
@@ -63,6 +68,7 @@ class QgsPluginSortFilterProxyModel : public QSortFilterProxyModel
6368

6469
private:
6570
QStringList mAcceptedStatuses;
71+
QString mAcceptedSpacers;
6672
};
6773

6874
#endif

‎src/app/qgisapp.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -629,11 +629,11 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, QWidget * parent,
629629

630630
if ( mPythonUtils && mPythonUtils->isEnabled() )
631631
{
632-
// pass the python utils to the plugin manager
633-
mPluginManager -> setPythonUtils( mPythonUtils );
634632
// initialize the plugin installer to start fetching repositories in background
635633
QgsPythonRunner::run( "import pyplugin_installer" );
636634
QgsPythonRunner::run( "pyplugin_installer.initPluginInstaller()" );
635+
// enable Python in the Plugin Manager and pass the PythonUtils to it
636+
mPluginManager -> setPythonUtils( mPythonUtils );
637637
}
638638

639639
mSplash->showMessage( tr( "Initializing file filters" ), Qt::AlignHCenter | Qt::AlignBottom );

‎src/ui/qgspluginmanagerbase.ui

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -470,28 +470,34 @@ padding: 0px</string>
470470
</spacer>
471471
</item>
472472
<item>
473-
<widget class="QPushButton" name="buttonInstall">
473+
<widget class="QPushButton" name="buttonUninstall">
474474
<property name="enabled">
475475
<bool>false</bool>
476476
</property>
477477
<property name="toolTip">
478-
<string>Install, reinstall or upgrade the selected plugin</string>
478+
<string>Uninstall the selected plugin</string>
479479
</property>
480480
<property name="text">
481-
<string>Install/upgrade plugin</string>
481+
<string>Uninstall plugin</string>
482482
</property>
483483
</widget>
484484
</item>
485485
<item>
486-
<widget class="QPushButton" name="buttonUninstall">
486+
<widget class="QPushButton" name="buttonInstall">
487487
<property name="enabled">
488488
<bool>false</bool>
489489
</property>
490+
<property name="minimumSize">
491+
<size>
492+
<width>180</width>
493+
<height>0</height>
494+
</size>
495+
</property>
490496
<property name="toolTip">
491-
<string>Uninstall the selected plugin</string>
497+
<string>Install, reinstall or upgrade the selected plugin</string>
492498
</property>
493499
<property name="text">
494-
<string>Uninstall plugin</string>
500+
<string>Reinstall plugin</string>
495501
</property>
496502
</widget>
497503
</item>
@@ -897,8 +903,8 @@ p, li { white-space: pre-wrap; }
897903
<tabstop>vwPlugins</tabstop>
898904
<tabstop>tbDetails</tabstop>
899905
<tabstop>buttonUpgradeAll</tabstop>
900-
<tabstop>buttonInstall</tabstop>
901906
<tabstop>buttonUninstall</tabstop>
907+
<tabstop>buttonInstall</tabstop>
902908
<tabstop>ckbCheckUpdates</tabstop>
903909
<tabstop>comboInterval</tabstop>
904910
<tabstop>ckbExperimental</tabstop>

0 commit comments

Comments
 (0)
Please sign in to comment.