Skip to content

Commit

Permalink
[Plugin Manager] Minor fixes and gui tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
borysiasty committed Jun 8, 2013
1 parent 0416a21 commit c0e7102
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 65 deletions.
6 changes: 6 additions & 0 deletions python/pyplugin_installer/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,12 @@ def onManagerClose(self):
repositories.saveCheckingOnStartLastDate()


# ----------------------------------------- #
def exportSettingsGroup(self):
""" Return QSettings settingsGroup value """
return settingsGroup


# ----------------------------------------- #
def upgradeAllUpgradeable(self):
""" Reinstall all upgradeable plugins """
Expand Down
40 changes: 27 additions & 13 deletions python/pyplugin_installer/installer_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@
from PyQt4.QtCore import *
from PyQt4.QtXml import QDomDocument
from PyQt4.QtNetwork import *
import sys
import os
import ConfigParser
import qgis.utils
from qgis.core import *
from qgis.utils import iface
from version_compare import compareVersions, normalizeVersion
import sys
import qgis.utils

"""
Data structure:
Expand Down Expand Up @@ -544,17 +546,29 @@ def removeRepository(self, repo):


# ----------------------------------------- #
def getInstalledPlugin(self, key, readOnly, testLoad=False):
def getInstalledPlugin(self, key, readOnly, testLoad=True):
""" get the metadata of an installed plugin """
def pluginMetadata(fct):
result = qgis.utils.pluginMetadata(key, fct)
if result == "__error__":
result = ""
return result
""" plugin metadata parser reimplemented from qgis.utils
for better control on wchich module is examined
in case there is an installed plugin masking a core one """
metadataFile = os.path.join(path, 'metadata.txt')
if not os.path.exists(metadataFile):
return "" # plugin has no metadata.txt file
cp = ConfigParser.ConfigParser()
res = cp.read(metadataFile)
if not len(res):
return "" # failed reading metadata.txt file
try:
return cp.get('general', fct)
except Exception:
return ""

path = QDir.cleanPath( QgsApplication.qgisSettingsDirPath() ) + "/python/plugins/" + key
if not QDir(path).exists():
if readOnly:
path = QDir.cleanPath( QgsApplication.pkgDataPath() ) + "/python/plugins/" + key
else:
path = QDir.cleanPath( QgsApplication.qgisSettingsDirPath() ) + "/python/plugins/" + key

if not QDir(path).exists():
return

Expand Down Expand Up @@ -633,7 +647,7 @@ def pluginMetadata(fct):


# ----------------------------------------- #
def getAllInstalled(self, testLoad=False):
def getAllInstalled(self, testLoad=True):
""" Build the localCache """
self.localCache = {}
# first, try to add the readonly plugins...
Expand All @@ -646,7 +660,7 @@ def getAllInstalled(self, testLoad=False):
for key in pluginDir.entryList():
key = unicode(key)
if not key in [".",".."]:
self.localCache[key] = self.getInstalledPlugin(key, True)
self.localCache[key] = self.getInstalledPlugin(key, readOnly=True, testLoad=False)
except:
# return QCoreApplication.translate("QgsPluginInstaller","Couldn't open the system plugin directory")
pass # it's not necessary to stop due to this error
Expand All @@ -662,7 +676,7 @@ def getAllInstalled(self, testLoad=False):
for key in pluginDir.entryList():
key = unicode(key)
if not key in [".",".."]:
plugin = self.getInstalledPlugin(key, False, testLoad)
plugin = self.getInstalledPlugin(key, readOnly=False, testLoad=testLoad)
if key in self.localCache.keys() and compareVersions(self.localCache[key]["version_installed"],plugin["version_installed"]) == 1:
# An obsolete plugin in the "user" location is masking a newer one in the "system" location!
self.obsoletePlugins += [key]
Expand Down Expand Up @@ -711,7 +725,7 @@ def rebuild(self):
self.mPlugins[key]["status"] = "orphan"
elif not self.mPlugins[key]["version_installed"]:
self.mPlugins[key]["status"] = "not installed"
elif self.mPlugins[key]["error"] in ["broken"] or self.mPlugins[key]["version_installed"] == "-1":
elif self.mPlugins[key]["version_installed"] in ["?", "-1"]:
self.mPlugins[key]["status"] = "installed"
elif compareVersions(self.mPlugins[key]["version_available"],self.mPlugins[key]["version_installed"]) == 0:
self.mPlugins[key]["status"] = "installed"
Expand Down
4 changes: 2 additions & 2 deletions src/app/pluginmanager/metadata
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pythonic true | false (is plugin pythonic or cpp?)
readonly true | false (is core plugin?)
installed true | false
available true | false
status not installed | new | upgradeable | orphan | newer *
status not installed | new | upgradeable | orphan | downgradeable *
error NULL | broken | incompatible | dependent
error_details
experimental choosen version status
Expand All @@ -34,4 +34,4 @@ rating_votes number of votes
available, installed. version_available, version_installed.
orphan = installed and not available to download;
new = not installed and seen for the first time;
newer = the installer version is newer than available one.
downgradeable = the available version is lower than installed one.
98 changes: 55 additions & 43 deletions src/app/pluginmanager/qgspluginmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,6 @@
#endif


// QSettings group constans
const QString reposGroup = "/Qgis/plugin-repos";
const QString settingsGroup = "/Qgis/plugin-installer";
const QString seenPluginGroup = "/Qgis/plugin-seen";


QgsPluginManager::QgsPluginManager( QWidget * parent, Qt::WFlags fl )
: QgsOptionsDialogBase( "PluginManager", parent, fl )
{
Expand All @@ -70,7 +64,14 @@ QgsPluginManager::QgsPluginManager( QWidget * parent, Qt::WFlags fl )
// and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots
initOptionsBase( true );

// init models
// Don't let QgsOptionsDialogBase to narrow the vertical tab list widget
mOptListWidget->setMaximumWidth( 16777215 );

// Restiore UI state for widgets not handled by QgsOptionsDialogBase
QSettings settings;
mPluginsDetailsSplitter->restoreState( settings.value( QString( "/Windows/PluginManager/secondSplitterState" ) ).toByteArray() );

// Init models
mModelPlugins = new QStandardItemModel( 0, 1 );
mModelProxy = new QgsPluginSortFilterProxyModel( this );
mModelProxy->setSourceModel( mModelPlugins );
Expand Down Expand Up @@ -112,6 +113,9 @@ QgsPluginManager::~QgsPluginManager()
{
delete mModelProxy;
delete mModelPlugins;

QSettings settings;
settings.setValue( QString( "/Windows/PluginManager/secondSplitterState" ), mPluginsDetailsSplitter->saveState() );
}


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

// get the QSettings group from the installer
QString settingsGroup;
QgsPythonRunner::eval( "pyplugin_installer.instance().exportSettingsGroup()", settingsGroup );

// Initialize list of allowed checking intervals
mCheckingOnStartIntervals << 0 << 1 << 3 << 7 << 14 << 30 ;

Expand Down Expand Up @@ -470,8 +478,9 @@ void QgsPluginManager::reloadModelData()
mypDetailItem->setFont( font );
}

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

// Set ckeckState depending on the plugin is loaded or not.
// Initially mark all unchecked, then overwrite state of loaded ones with checked.
Expand Down Expand Up @@ -501,10 +510,10 @@ void QgsPluginManager::reloadModelData()
if ( mPythonUtils && mPythonUtils->isEnabled() )
{
// TODO: implement better sort method instead of these dummy -Z statuses
mModelPlugins->appendRow( createSpacerItem( tr( "Reinstallable plugins", "category: plugins that are installed and available" ) , "installedZ" ) );
if ( hasUpgradeablePlugins() ) mModelPlugins->appendRow( createSpacerItem( tr( "Upgradeable plugins", "category: plugins that are installed and there is newer version available" ), "upgradeableZ") );
mModelPlugins->appendRow( createSpacerItem( tr( "Reinstallable", "category: plugins that are installed and available" ) , "installedZ" ) );
if ( hasUpgradeablePlugins() ) mModelPlugins->appendRow( createSpacerItem( tr( "Upgradeable", "category: plugins that are installed and there is a newer version available" ), "upgradeableZ") );
mModelPlugins->appendRow( createSpacerItem( tr( "Only locally available", "category: plugins that are only locally available" ), "orphanZ" ) );
if ( hasNewerPlugins() ) mModelPlugins->appendRow( createSpacerItem( tr( "Newer locally", "category: plugins installed and availabie; installed version is newer" ), "newerZ" ) );
if ( hasNewerPlugins() ) mModelPlugins->appendRow( createSpacerItem( tr( "Downgradeable", "category: plugins that are installed and there is an OLDER version available" ), "newerZ" ) );
}

updateTabTitle();
Expand All @@ -530,7 +539,6 @@ void QgsPluginManager::pluginItemChanged( QStandardItem * item )
}
else if ( ! item->checkState() )
{
// don't test if isPluginLoaded, to allow disable also plugins taht weren't successfully loaded
QgsDebugMsg( " Unloading plugin: " + id );
unloadPlugin( id );
}
Expand Down Expand Up @@ -579,7 +587,7 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
{
errorMsg = QString( "<b>%1</b><br/>%2" ).arg( tr( "This plugin is broken" ) ).arg( metadata->value( "error_details" ) );
}
html += QString( "<table bgcolor=\"#EEEE00\" cellspacing=\"2\" cellpadding=\"6\" width=\"100%\">"
html += QString( "<table bgcolor=\"#FFFF88\" cellspacing=\"2\" cellpadding=\"6\" width=\"100%\">"
" <tr><td width=\"100%\" style=\"color:#CC0000\">%1</td></tr>"
"</table>" ).arg( errorMsg );
}
Expand Down Expand Up @@ -625,7 +633,23 @@ void QgsPluginManager::showPluginDetails( QStandardItem * item )
html += QString( "<img src=\"%1\" style=\"float:right;\">" ).arg( metadata->value( "icon" ) );
}

html += QString( "<h3>%2</h3>" ).arg( metadata->value( "description" ) );
html += QString( "<h3>%2</h3><br/>" ).arg( metadata->value( "description" ) );

if ( ! metadata->value( "average_vote" ).isEmpty() )
{
// draw stars
int stars = qRound( metadata->value( "average_vote" ).toFloat() );
for ( int i = 0; i < stars; i++ )
{
html += "<img src=\":/images/themes/default/mIconNew.png\">";
}
html += tr( "<br/>%1 rating vote(s)<br/>" ).arg( metadata->value( "rating_votes" ) );
}
if ( ! metadata->value( "downloads" ).isEmpty() )
{
html += tr( "%1 downloads<br/>" ).arg( metadata->value( "downloads" ) );
html += "<br/>";
}

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

if ( ! metadata->value( "average_vote" ).isEmpty() )
{
// draw stars
int stars = qRound( metadata->value( "average_vote" ).toFloat() );
for ( int i = 0; i < stars; i++ )
{
html += "<img src=\":/images/themes/default/mIconNew.png\">";
}
html += tr( "<br/>%1 rating vote(s)<br/>" ).arg( metadata->value( "rating_votes" ) );
}
if ( ! metadata->value( "downloads" ).isEmpty() )
{
html += tr( "%1 downloads<br/>" ).arg( metadata->value( "downloads" ) );
}

html += "<br/>" ;

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

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

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

void QgsPluginManager::on_ckbExperimental_toggled( bool state )
{
QString settingsGroup;
QgsPythonRunner::eval( "pyplugin_installer.instance().exportSettingsGroup()", settingsGroup );
QSettings settings;
settings.setValue( settingsGroup + "/allowExperimental", QVariant( state ) );
QgsPythonRunner::run( "pyplugin_installer.installer_data.plugins.rebuild()" );
Expand All @@ -1132,27 +1146,25 @@ bool QgsPluginManager::isPluginLoaded( QString key )
QMap<QString, QString>* plugin = pluginMetadata( key );
if ( plugin->isEmpty() )
{
// No such plugin in the metadata registry
return false;
}

QString library = key;
if ( plugin->value( "pythonic" ) != "true" )
{
// trim "cpp:" prefix from cpp plugin id
// For C++ plugins, just check in the QgsPluginRegistry. If the plugin is broken, it was disabled quietly.
// Trim "cpp:" prefix from cpp plugin id
key = key.mid( 4 );
library = plugin->value( "library" );
QgsPluginRegistry *pRegistry = QgsPluginRegistry::instance();
return pRegistry->isLoaded( key );
}

QgsPluginRegistry *pRegistry = QgsPluginRegistry::instance();
if ( pRegistry->isLoaded( key ) )
else
{
// TODO: this check shouldn't be necessary, plugin base names must be unique
if ( pRegistry->library( key ) == library )
{
return true;
}
// For Python plugins, check in QSettings if enabled rather than checking in QgsPluginRegistry if loaded.
// This will allow to turn off the plugin if broken.
QSettings mySettings;
return ( plugin->value( "installed" ) == "true" && mySettings.value( "/PythonPlugins/" + key, QVariant( false ) ).toBool() );
}
return false;
}


Expand Down
2 changes: 1 addition & 1 deletion src/app/pluginmanager/qgspluginmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ class QgsPluginManager : public QgsOptionsDialogBase, private Ui::QgsPluginManag
void enableSelectedRepositoryOnly( bool checked );

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

//! Return true if there are plugins available for download in the metadata registry
Expand Down
Loading

0 comments on commit c0e7102

Please sign in to comment.