@@ -60,6 +60,9 @@ const QString seenPluginGroup = "/Qgis/plugin-seen";
60
60
QgsPluginManager::QgsPluginManager ( QWidget * parent, Qt::WFlags fl )
61
61
: QgsOptionsDialogBase( " PluginManager" , parent, fl )
62
62
{
63
+ // initialize pointer
64
+ mPythonUtils = NULL ;
65
+
63
66
setupUi ( this );
64
67
65
68
// QgsOptionsDialogBase handles saving/restoring of geometry, splitter and current tab states,
@@ -72,63 +75,92 @@ QgsPluginManager::QgsPluginManager( QWidget * parent, Qt::WFlags fl )
72
75
mModelProxy = new QgsPluginSortFilterProxyModel ( this );
73
76
mModelProxy ->setSourceModel ( mModelPlugins );
74
77
mModelProxy ->setSortCaseSensitivity ( Qt::CaseInsensitive );
78
+ mModelProxy ->setSortRole ( Qt::DisplayRole );
79
+ mModelProxy ->setDynamicSortFilter ( true );
75
80
vwPlugins->setModel ( mModelProxy );
76
81
vwPlugins->setFocus ();
77
82
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
79
136
QAction* actionSortByName = new QAction ( tr ( " sort by name" ), vwPlugins );
80
137
QAction* actionSortByDownloads = new QAction ( tr ( " sort by downloads" ), vwPlugins );
81
138
QAction* actionSortByVote = new QAction ( tr ( " sort by vote" ), vwPlugins );
82
139
QAction* actionSortByStatus = new QAction ( tr ( " sort by status" ), vwPlugins );
83
- QAction* actionSortByRepository = new QAction ( tr ( " sort by repository" ), vwPlugins );
84
140
actionSortByName->setCheckable ( true );
85
141
actionSortByDownloads->setCheckable ( true );
86
142
actionSortByVote->setCheckable ( true );
87
143
actionSortByStatus->setCheckable ( true );
88
- actionSortByRepository->setCheckable ( true );
89
144
QActionGroup * group = new QActionGroup ( vwPlugins );
90
145
actionSortByName->setActionGroup ( group );
91
146
actionSortByDownloads->setActionGroup ( group );
92
147
actionSortByVote->setActionGroup ( group );
93
148
actionSortByStatus->setActionGroup ( group );
94
- actionSortByRepository->setActionGroup ( group );
95
149
actionSortByName->setChecked ( true );
96
150
vwPlugins->addAction ( actionSortByName );
97
151
vwPlugins->addAction ( actionSortByDownloads );
98
152
vwPlugins->addAction ( actionSortByVote );
99
153
vwPlugins->addAction ( actionSortByStatus );
100
- vwPlugins->addAction ( actionSortByRepository );
101
154
vwPlugins->setContextMenuPolicy ( Qt::ActionsContextMenu );
102
155
connect ( actionSortByName, SIGNAL ( triggered ( ) ), mModelProxy , SLOT ( sortPluginsByName ( ) ) );
103
156
connect ( actionSortByDownloads, SIGNAL ( triggered ( ) ), mModelProxy , SLOT ( sortPluginsByDownloads ( ) ) );
104
157
connect ( actionSortByVote, SIGNAL ( triggered ( ) ), mModelProxy , SLOT ( sortPluginsByVote ( ) ) );
105
158
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 );
127
159
128
160
// Initialize list of allowed checking intervals
129
- checkingOnStartIntervals << 0 << 1 << 3 << 7 << 14 << 30 ;
161
+ mCheckingOnStartIntervals << 0 << 1 << 3 << 7 << 14 << 30 ;
130
162
131
- // Initialize the "Setting " tab widgets
163
+ // Initialize the "Settings " tab widgets
132
164
QSettings settings;
133
165
if ( settings.value ( settingsGroup + " /checkOnStart" , false ).toBool () )
134
166
{
@@ -141,27 +173,12 @@ QgsPluginManager::QgsPluginManager( QWidget * parent, Qt::WFlags fl )
141
173
}
142
174
143
175
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.
145
177
comboInterval->setCurrentIndex ( indx );
146
178
}
147
179
148
180
149
181
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
-
165
182
void QgsPluginManager::loadPlugin ( QString id )
166
183
{
167
184
QMap<QString, QString>* plugin = pluginMetadata ( id );
@@ -220,7 +237,7 @@ void QgsPluginManager::unloadPlugin( QString id )
220
237
221
238
222
239
223
- void QgsPluginManager::getCppPluginDescriptions ()
240
+ void QgsPluginManager::getCppPluginsMetadata ()
224
241
{
225
242
QString sharedLibExtension;
226
243
#if defined(WIN32) || defined(__CYGWIN__)
@@ -371,6 +388,7 @@ void QgsPluginManager::getCppPluginDescriptions()
371
388
metadata[" pythonic" ] = " false" ;
372
389
metadata[" installed" ] = " true" ;
373
390
metadata[" readonly" ] = " true" ;
391
+ metadata[" status" ] = " orphan" ;
374
392
metadata[" experimental" ] = ( pExperimental ? pExperimental () : QString () );
375
393
mPlugins .insert ( baseName, metadata );
376
394
@@ -381,6 +399,22 @@ void QgsPluginManager::getCppPluginDescriptions()
381
399
382
400
383
401
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
+
384
418
void QgsPluginManager::reloadModelData ()
385
419
{
386
420
mModelPlugins ->clear ();
@@ -389,7 +423,6 @@ void QgsPluginManager::reloadModelData()
389
423
it != mPlugins .end ();
390
424
it++ )
391
425
{
392
-
393
426
if ( ! it->value ( " id" ).isEmpty () )
394
427
{
395
428
QString baseName = it->value ( " id" );
@@ -464,11 +497,22 @@ void QgsPluginManager::reloadModelData()
464
497
}
465
498
}
466
499
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
+
467
510
updateTabTitle ();
468
511
469
512
buttonUpgradeAll->setEnabled ( hasUpgradeablePlugins () );
470
513
471
514
// Disable tabs that are empty because of no suitable plugins in the model.
515
+ mOptionsListWidget ->item ( 1 )->setHidden ( ! hasAvailablePlugins () );
472
516
mOptionsListWidget ->item ( 2 )->setHidden ( ! hasUpgradeablePlugins () );
473
517
mOptionsListWidget ->item ( 3 )->setHidden ( ! hasNewPlugins () );
474
518
mOptionsListWidget ->item ( 4 )->setHidden ( ! hasInvalidPlugins () );
@@ -525,11 +569,11 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
525
569
QString errorMsg;
526
570
if ( metadata->value ( " error" ) == " incompatible" )
527
571
{
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" ) ) );
529
573
}
530
574
else if ( metadata->value ( " error" ) == " dependent" )
531
575
{
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" ) );
533
577
}
534
578
else
535
579
{
@@ -665,22 +709,20 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
665
709
{
666
710
buttonInstall->setText ( tr ( " Downgrade plugin" ) );
667
711
}
668
- else if ( metadata->value ( " status" ) == " installed" )
669
- {
670
- buttonInstall->setText ( tr ( " Reinstall plugin" ) );
671
- }
672
712
else if ( metadata->value ( " status" ) == " not installed" || metadata->value ( " status" ) == " new" )
673
713
{
674
714
buttonInstall->setText ( tr ( " Install plugin" ) );
675
715
}
676
716
else
677
717
{
678
- buttonInstall->setText ( tr ( " Install/upgrade plugin" ) );
718
+ // Default (will be grayed out if not available for reinstallation)
719
+ buttonInstall->setText ( tr ( " Reinstall plugin" ) );
679
720
}
680
721
681
722
// Enable/disable buttons
682
723
buttonInstall->setEnabled ( metadata->value ( " pythonic" ).toUpper () == " TRUE" && metadata->value ( " status" ) != " orphan" );
683
724
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" );
684
726
685
727
// Store the id of the currently displayed plugin
686
728
mCurrentlyDisplayedPlugin = metadata->value ( " id" );
@@ -743,6 +785,16 @@ void QgsPluginManager::clearRepositoryList()
743
785
// ! Add repository to the repository listWidget
744
786
void QgsPluginManager::addToRepositoryList ( QMap<QString, QString> repository )
745
787
{
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
+
746
798
QString key = repository.value ( " name" );
747
799
if ( ! key.isEmpty () )
748
800
{
@@ -795,14 +847,16 @@ void QgsPluginManager::addToRepositoryList( QMap<QString, QString> repository )
795
847
// SLOTS ///////////////////////////////////////////////////////////////////
796
848
797
849
798
-
799
850
// "Close" button clicked
800
851
void QgsPluginManager::reject ()
801
852
{
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
+ }
806
860
done ( 1 );
807
861
}
808
862
@@ -824,8 +878,8 @@ void QgsPluginManager::setCurrentTab( int idx )
824
878
switch ( idx )
825
879
{
826
880
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 " << " " ;
829
883
break ;
830
884
case 1 :
831
885
// not installed (get more)
@@ -996,6 +1050,26 @@ void QgsPluginManager::on_treeRepositories_doubleClicked( QModelIndex )
996
1050
997
1051
998
1052
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
+
999
1073
void QgsPluginManager::on_buttonRefreshRepos_clicked ( )
1000
1074
{
1001
1075
QgsDebugMsg ( " Refreshing repositories..." );
@@ -1053,7 +1127,6 @@ void QgsPluginManager::on_ckbExperimental_toggled( bool state )
1053
1127
// PRIVATE METHODS ///////////////////////////////////////////////////////////////////
1054
1128
1055
1129
1056
-
1057
1130
bool QgsPluginManager::isPluginLoaded ( QString key )
1058
1131
{
1059
1132
QMap<QString, QString>* plugin = pluginMetadata ( key );
@@ -1083,6 +1156,21 @@ bool QgsPluginManager::isPluginLoaded( QString key )
1083
1156
}
1084
1157
1085
1158
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
+
1086
1174
1087
1175
bool QgsPluginManager::hasUpgradeablePlugins ( )
1088
1176
{
@@ -1118,6 +1206,23 @@ bool QgsPluginManager::hasNewPlugins( )
1118
1206
1119
1207
1120
1208
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
+
1121
1226
bool QgsPluginManager::hasInvalidPlugins ( )
1122
1227
{
1123
1228
for ( QMap<QString, QMap<QString, QString> >::iterator it = mPlugins .begin ();
0 commit comments