Skip to content

Commit c0e7102

Browse files
committedJun 8, 2013
[Plugin Manager] Minor fixes and gui tweaks
1 parent 0416a21 commit c0e7102

File tree

6 files changed

+112
-65
lines changed

6 files changed

+112
-65
lines changed
 

‎python/pyplugin_installer/installer.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,12 @@ def onManagerClose(self):
242242
repositories.saveCheckingOnStartLastDate()
243243

244244

245+
# ----------------------------------------- #
246+
def exportSettingsGroup(self):
247+
""" Return QSettings settingsGroup value """
248+
return settingsGroup
249+
250+
245251
# ----------------------------------------- #
246252
def upgradeAllUpgradeable(self):
247253
""" Reinstall all upgradeable plugins """

‎python/pyplugin_installer/installer_data.py

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@
2626
from PyQt4.QtCore import *
2727
from PyQt4.QtXml import QDomDocument
2828
from PyQt4.QtNetwork import *
29+
import sys
30+
import os
31+
import ConfigParser
32+
import qgis.utils
2933
from qgis.core import *
3034
from qgis.utils import iface
3135
from version_compare import compareVersions, normalizeVersion
32-
import sys
33-
import qgis.utils
3436

3537
"""
3638
Data structure:
@@ -544,17 +546,29 @@ def removeRepository(self, repo):
544546

545547

546548
# ----------------------------------------- #
547-
def getInstalledPlugin(self, key, readOnly, testLoad=False):
549+
def getInstalledPlugin(self, key, readOnly, testLoad=True):
548550
""" get the metadata of an installed plugin """
549551
def pluginMetadata(fct):
550-
result = qgis.utils.pluginMetadata(key, fct)
551-
if result == "__error__":
552-
result = ""
553-
return result
552+
""" plugin metadata parser reimplemented from qgis.utils
553+
for better control on wchich module is examined
554+
in case there is an installed plugin masking a core one """
555+
metadataFile = os.path.join(path, 'metadata.txt')
556+
if not os.path.exists(metadataFile):
557+
return "" # plugin has no metadata.txt file
558+
cp = ConfigParser.ConfigParser()
559+
res = cp.read(metadataFile)
560+
if not len(res):
561+
return "" # failed reading metadata.txt file
562+
try:
563+
return cp.get('general', fct)
564+
except Exception:
565+
return ""
554566

555-
path = QDir.cleanPath( QgsApplication.qgisSettingsDirPath() ) + "/python/plugins/" + key
556-
if not QDir(path).exists():
567+
if readOnly:
557568
path = QDir.cleanPath( QgsApplication.pkgDataPath() ) + "/python/plugins/" + key
569+
else:
570+
path = QDir.cleanPath( QgsApplication.qgisSettingsDirPath() ) + "/python/plugins/" + key
571+
558572
if not QDir(path).exists():
559573
return
560574

@@ -633,7 +647,7 @@ def pluginMetadata(fct):
633647

634648

635649
# ----------------------------------------- #
636-
def getAllInstalled(self, testLoad=False):
650+
def getAllInstalled(self, testLoad=True):
637651
""" Build the localCache """
638652
self.localCache = {}
639653
# first, try to add the readonly plugins...
@@ -646,7 +660,7 @@ def getAllInstalled(self, testLoad=False):
646660
for key in pluginDir.entryList():
647661
key = unicode(key)
648662
if not key in [".",".."]:
649-
self.localCache[key] = self.getInstalledPlugin(key, True)
663+
self.localCache[key] = self.getInstalledPlugin(key, readOnly=True, testLoad=False)
650664
except:
651665
# return QCoreApplication.translate("QgsPluginInstaller","Couldn't open the system plugin directory")
652666
pass # it's not necessary to stop due to this error
@@ -662,7 +676,7 @@ def getAllInstalled(self, testLoad=False):
662676
for key in pluginDir.entryList():
663677
key = unicode(key)
664678
if not key in [".",".."]:
665-
plugin = self.getInstalledPlugin(key, False, testLoad)
679+
plugin = self.getInstalledPlugin(key, readOnly=False, testLoad=testLoad)
666680
if key in self.localCache.keys() and compareVersions(self.localCache[key]["version_installed"],plugin["version_installed"]) == 1:
667681
# An obsolete plugin in the "user" location is masking a newer one in the "system" location!
668682
self.obsoletePlugins += [key]
@@ -711,7 +725,7 @@ def rebuild(self):
711725
self.mPlugins[key]["status"] = "orphan"
712726
elif not self.mPlugins[key]["version_installed"]:
713727
self.mPlugins[key]["status"] = "not installed"
714-
elif self.mPlugins[key]["error"] in ["broken"] or self.mPlugins[key]["version_installed"] == "-1":
728+
elif self.mPlugins[key]["version_installed"] in ["?", "-1"]:
715729
self.mPlugins[key]["status"] = "installed"
716730
elif compareVersions(self.mPlugins[key]["version_available"],self.mPlugins[key]["version_installed"]) == 0:
717731
self.mPlugins[key]["status"] = "installed"

‎src/app/pluginmanager/metadata

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pythonic true | false (is plugin pythonic or cpp?)
1818
readonly true | false (is core plugin?)
1919
installed true | false
2020
available true | false
21-
status not installed | new | upgradeable | orphan | newer *
21+
status not installed | new | upgradeable | orphan | downgradeable *
2222
error NULL | broken | incompatible | dependent
2323
error_details
2424
experimental choosen version status
@@ -34,4 +34,4 @@ rating_votes number of votes
3434
available, installed. version_available, version_installed.
3535
orphan = installed and not available to download;
3636
new = not installed and seen for the first time;
37-
newer = the installer version is newer than available one.
37+
downgradeable = the available version is lower than installed one.

‎src/app/pluginmanager/qgspluginmanager.cpp

Lines changed: 55 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,6 @@
5151
#endif
5252

5353

54-
// QSettings group constans
55-
const QString reposGroup = "/Qgis/plugin-repos";
56-
const QString settingsGroup = "/Qgis/plugin-installer";
57-
const QString seenPluginGroup = "/Qgis/plugin-seen";
58-
59-
6054
QgsPluginManager::QgsPluginManager( QWidget * parent, Qt::WFlags fl )
6155
: QgsOptionsDialogBase( "PluginManager", parent, fl )
6256
{
@@ -70,7 +64,14 @@ QgsPluginManager::QgsPluginManager( QWidget * parent, Qt::WFlags fl )
7064
// and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots
7165
initOptionsBase( true );
7266

73-
// init models
67+
// Don't let QgsOptionsDialogBase to narrow the vertical tab list widget
68+
mOptListWidget->setMaximumWidth( 16777215 );
69+
70+
// Restiore UI state for widgets not handled by QgsOptionsDialogBase
71+
QSettings settings;
72+
mPluginsDetailsSplitter->restoreState( settings.value( QString( "/Windows/PluginManager/secondSplitterState" ) ).toByteArray() );
73+
74+
// Init models
7475
mModelPlugins = new QStandardItemModel( 0, 1 );
7576
mModelProxy = new QgsPluginSortFilterProxyModel( this );
7677
mModelProxy->setSourceModel( mModelPlugins );
@@ -112,6 +113,9 @@ QgsPluginManager::~QgsPluginManager()
112113
{
113114
delete mModelProxy;
114115
delete mModelPlugins;
116+
117+
QSettings settings;
118+
settings.setValue( QString( "/Windows/PluginManager/secondSplitterState" ), mPluginsDetailsSplitter->saveState() );
115119
}
116120

117121

@@ -157,6 +161,10 @@ void QgsPluginManager::setPythonUtils( QgsPythonUtils* pythonUtils )
157161
connect( actionSortByVote, SIGNAL( triggered( ) ), mModelProxy, SLOT( sortPluginsByVote( ) ) );
158162
connect( actionSortByStatus, SIGNAL( triggered( ) ), mModelProxy, SLOT( sortPluginsByStatus( ) ) );
159163

164+
// get the QSettings group from the installer
165+
QString settingsGroup;
166+
QgsPythonRunner::eval( "pyplugin_installer.instance().exportSettingsGroup()", settingsGroup );
167+
160168
// Initialize list of allowed checking intervals
161169
mCheckingOnStartIntervals << 0 << 1 << 3 << 7 << 14 << 30 ;
162170

@@ -470,8 +478,9 @@ void QgsPluginManager::reloadModelData()
470478
mypDetailItem->setFont( font );
471479
}
472480

473-
// set checkable if the plugin is loadable.
474-
mypDetailItem->setCheckable( it->value( "installed" ) == "true" && it->value( "error" ).isEmpty() );
481+
// Set checkable if the plugin is installed and not disabled due to incompatibility.
482+
// Broken plugins are checkable to to allow disabling them
483+
mypDetailItem->setCheckable( it->value( "installed" ) == "true" && it->value( "error" ) != "incompatible" );
475484

476485
// Set ckeckState depending on the plugin is loaded or not.
477486
// Initially mark all unchecked, then overwrite state of loaded ones with checked.
@@ -501,10 +510,10 @@ void QgsPluginManager::reloadModelData()
501510
if ( mPythonUtils && mPythonUtils->isEnabled() )
502511
{
503512
// 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") );
513+
mModelPlugins->appendRow( createSpacerItem( tr( "Reinstallable", "category: plugins that are installed and available" ) , "installedZ" ) );
514+
if ( hasUpgradeablePlugins() ) mModelPlugins->appendRow( createSpacerItem( tr( "Upgradeable", "category: plugins that are installed and there is a newer version available" ), "upgradeableZ") );
506515
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" ) );
516+
if ( hasNewerPlugins() ) mModelPlugins->appendRow( createSpacerItem( tr( "Downgradeable", "category: plugins that are installed and there is an OLDER version available" ), "newerZ" ) );
508517
}
509518

510519
updateTabTitle();
@@ -530,7 +539,6 @@ void QgsPluginManager::pluginItemChanged( QStandardItem * item )
530539
}
531540
else if ( ! item->checkState() )
532541
{
533-
// don't test if isPluginLoaded, to allow disable also plugins taht weren't successfully loaded
534542
QgsDebugMsg( " Unloading plugin: " + id );
535543
unloadPlugin( id );
536544
}
@@ -579,7 +587,7 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
579587
{
580588
errorMsg = QString( "<b>%1</b><br/>%2" ).arg( tr( "This plugin is broken" ) ).arg( metadata->value( "error_details" ) );
581589
}
582-
html += QString( "<table bgcolor=\"#EEEE00\" cellspacing=\"2\" cellpadding=\"6\" width=\"100%\">"
590+
html += QString( "<table bgcolor=\"#FFFF88\" cellspacing=\"2\" cellpadding=\"6\" width=\"100%\">"
583591
" <tr><td width=\"100%\" style=\"color:#CC0000\">%1</td></tr>"
584592
"</table>" ).arg( errorMsg );
585593
}
@@ -625,7 +633,23 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
625633
html += QString( "<img src=\"%1\" style=\"float:right;\">" ).arg( metadata->value( "icon" ) );
626634
}
627635

628-
html += QString( "<h3>%2</h3>" ).arg( metadata->value( "description" ) );
636+
html += QString( "<h3>%2</h3><br/>" ).arg( metadata->value( "description" ) );
637+
638+
if ( ! metadata->value( "average_vote" ).isEmpty() )
639+
{
640+
// draw stars
641+
int stars = qRound( metadata->value( "average_vote" ).toFloat() );
642+
for ( int i = 0; i < stars; i++ )
643+
{
644+
html += "<img src=\":/images/themes/default/mIconNew.png\">";
645+
}
646+
html += tr( "<br/>%1 rating vote(s)<br/>" ).arg( metadata->value( "rating_votes" ) );
647+
}
648+
if ( ! metadata->value( "downloads" ).isEmpty() )
649+
{
650+
html += tr( "%1 downloads<br/>" ).arg( metadata->value( "downloads" ) );
651+
html += "<br/>";
652+
}
629653

630654
if ( ! metadata->value( "category" ).isEmpty() )
631655
{
@@ -661,21 +685,6 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
661685
html += "<br/>";
662686
}
663687

664-
if ( ! metadata->value( "average_vote" ).isEmpty() )
665-
{
666-
// draw stars
667-
int stars = qRound( metadata->value( "average_vote" ).toFloat() );
668-
for ( int i = 0; i < stars; i++ )
669-
{
670-
html += "<img src=\":/images/themes/default/mIconNew.png\">";
671-
}
672-
html += tr( "<br/>%1 rating vote(s)<br/>" ).arg( metadata->value( "rating_votes" ) );
673-
}
674-
if ( ! metadata->value( "downloads" ).isEmpty() )
675-
{
676-
html += tr( "%1 downloads<br/>" ).arg( metadata->value( "downloads" ) );
677-
}
678-
679688
html += "<br/>" ;
680689

681690
if ( ! metadata->value( "version_installed" ).isEmpty() )
@@ -721,7 +730,7 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
721730

722731
// Enable/disable buttons
723732
buttonInstall->setEnabled( metadata->value( "pythonic" ).toUpper() == "TRUE" && metadata->value( "status" ) != "orphan" );
724-
buttonUninstall->setEnabled( metadata->value( "pythonic" ).toUpper() == "TRUE" && metadata->value( "status" ) != "readonly" && metadata->value( "status" ) != "not installed" && metadata->value( "status" ) != "new" );
733+
buttonUninstall->setEnabled( metadata->value( "pythonic" ).toUpper() == "TRUE" && metadata->value( "readonly" ) != "true" && metadata->value( "status" ) != "not installed" && metadata->value( "status" ) != "new" );
725734
buttonUninstall->setHidden( metadata->value( "status" ) == "not installed" || metadata->value( "status" ) == "new" );
726735

727736
// Store the id of the currently displayed plugin
@@ -852,6 +861,9 @@ void QgsPluginManager::reject()
852861
{
853862
if ( mPythonUtils && mPythonUtils->isEnabled() )
854863
{
864+
// get the QSettings group from the installer
865+
QString settingsGroup;
866+
QgsPythonRunner::eval( "pyplugin_installer.instance().exportSettingsGroup()", settingsGroup );
855867
QSettings settings;
856868
settings.setValue( settingsGroup + "/checkOnStart", QVariant( ckbCheckUpdates->isChecked() ) );
857869
settings.setValue( settingsGroup + "/checkOnStartInterval", QVariant( mCheckingOnStartIntervals.value( comboInterval->currentIndex() ) ) );
@@ -1116,6 +1128,8 @@ void QgsPluginManager::on_buttonDeleteRep_clicked( )
11161128

11171129
void QgsPluginManager::on_ckbExperimental_toggled( bool state )
11181130
{
1131+
QString settingsGroup;
1132+
QgsPythonRunner::eval( "pyplugin_installer.instance().exportSettingsGroup()", settingsGroup );
11191133
QSettings settings;
11201134
settings.setValue( settingsGroup + "/allowExperimental", QVariant( state ) );
11211135
QgsPythonRunner::run( "pyplugin_installer.installer_data.plugins.rebuild()" );
@@ -1132,27 +1146,25 @@ bool QgsPluginManager::isPluginLoaded( QString key )
11321146
QMap<QString, QString>* plugin = pluginMetadata( key );
11331147
if ( plugin->isEmpty() )
11341148
{
1149+
// No such plugin in the metadata registry
11351150
return false;
11361151
}
11371152

1138-
QString library = key;
11391153
if ( plugin->value( "pythonic" ) != "true" )
11401154
{
1141-
// trim "cpp:" prefix from cpp plugin id
1155+
// For C++ plugins, just check in the QgsPluginRegistry. If the plugin is broken, it was disabled quietly.
1156+
// Trim "cpp:" prefix from cpp plugin id
11421157
key = key.mid( 4 );
1143-
library = plugin->value( "library" );
1158+
QgsPluginRegistry *pRegistry = QgsPluginRegistry::instance();
1159+
return pRegistry->isLoaded( key );
11441160
}
1145-
1146-
QgsPluginRegistry *pRegistry = QgsPluginRegistry::instance();
1147-
if ( pRegistry->isLoaded( key ) )
1161+
else
11481162
{
1149-
// TODO: this check shouldn't be necessary, plugin base names must be unique
1150-
if ( pRegistry->library( key ) == library )
1151-
{
1152-
return true;
1153-
}
1163+
// For Python plugins, check in QSettings if enabled rather than checking in QgsPluginRegistry if loaded.
1164+
// This will allow to turn off the plugin if broken.
1165+
QSettings mySettings;
1166+
return ( plugin->value( "installed" ) == "true" && mySettings.value( "/PythonPlugins/" + key, QVariant( false ) ).toBool() );
11541167
}
1155-
return false;
11561168
}
11571169

11581170

‎src/app/pluginmanager/qgspluginmanager.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ class QgsPluginManager : public QgsOptionsDialogBase, private Ui::QgsPluginManag
160160
void enableSelectedRepositoryOnly( bool checked );
161161

162162
private:
163-
//! Return true if given plugin is currently present in QgsPluginRegistry
163+
//! Return true if given plugin is present in QgsPluginRegistry (c++ plugins) or is enabled in QSettings (Python plugins)
164164
bool isPluginLoaded( QString key );
165165

166166
//! Return true if there are plugins available for download in the metadata registry

‎src/ui/qgspluginmanagerbase.ui

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>780</width>
10-
<height>519</height>
9+
<width>857</width>
10+
<height>507</height>
1111
</rect>
1212
</property>
1313
<property name="minimumSize">
1414
<size>
15-
<width>780</width>
15+
<width>790</width>
1616
<height>0</height>
1717
</size>
1818
</property>
@@ -73,7 +73,7 @@
7373
</property>
7474
<property name="minimumSize">
7575
<size>
76-
<width>52</width>
76+
<width>140</width>
7777
<height>0</height>
7878
</size>
7979
</property>
@@ -387,19 +387,28 @@
387387
</property>
388388
<property name="minimumSize">
389389
<size>
390-
<width>250</width>
390+
<width>200</width>
391391
<height>0</height>
392392
</size>
393393
</property>
394+
<property name="horizontalScrollBarPolicy">
395+
<enum>Qt::ScrollBarAlwaysOff</enum>
396+
</property>
394397
<property name="showDropIndicator" stdset="0">
395398
<bool>false</bool>
396399
</property>
400+
<property name="alternatingRowColors">
401+
<bool>false</bool>
402+
</property>
397403
<property name="selectionMode">
398404
<enum>QAbstractItemView::SingleSelection</enum>
399405
</property>
400406
<property name="selectionBehavior">
401407
<enum>QAbstractItemView::SelectItems</enum>
402408
</property>
409+
<property name="resizeMode">
410+
<enum>QListView::Adjust</enum>
411+
</property>
403412
<property name="wordWrap">
404413
<bool>false</bool>
405414
</property>
@@ -423,6 +432,12 @@
423432
<verstretch>0</verstretch>
424433
</sizepolicy>
425434
</property>
435+
<property name="minimumSize">
436+
<size>
437+
<width>0</width>
438+
<height>0</height>
439+
</size>
440+
</property>
426441
<property name="acceptDrops">
427442
<bool>false</bool>
428443
</property>
@@ -489,7 +504,7 @@ padding: 0px</string>
489504
</property>
490505
<property name="minimumSize">
491506
<size>
492-
<width>180</width>
507+
<width>160</width>
493508
<height>0</height>
494509
</size>
495510
</property>

0 commit comments

Comments
 (0)
Please sign in to comment.