735 changes: 735 additions & 0 deletions images/themes/default/propertyicons/plugin-installed.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
713 changes: 713 additions & 0 deletions images/themes/default/propertyicons/plugin.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
745 changes: 745 additions & 0 deletions images/themes/default/propertyicons/plugins.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
579 changes: 579 additions & 0 deletions images/themes/default/propertyicons/settings.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/themes/default/repositoryConnected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/themes/default/repositoryDisabled.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/themes/default/repositoryUnavailable.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ SET (PYTHON_OUTPUT_DIRECTORY ${QGIS_OUTPUT_DIRECTORY}/python)
ADD_SUBDIRECTORY(plugins)
ADD_SUBDIRECTORY(qsci_apis)
ADD_SUBDIRECTORY(console)
ADD_SUBDIRECTORY(pyplugin_installer)

IF (WITH_PYSPATIALITE)
ADD_SUBDIRECTORY(pyspatialite)
Expand Down
1 change: 1 addition & 0 deletions python/gui/gui.sip
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
%Include qgsgenericprojectionselector.sip
%Include qgshtmlannotationitem.sip
%Include qgslegendinterface.sip
%Include qgspluginmanagerinterface.sip
%Include qgslonglongvalidator.sip
%Include qgsludialog.sip
%Include qgsmanageconnectionsdialog.sip
Expand Down
2 changes: 2 additions & 0 deletions python/gui/qgisinterface.sip
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class QgisInterface : QObject
*/
virtual QgsLegendInterface* legendInterface() = 0;

virtual QgsPluginManagerInterface* pluginManagerInterface() = 0;

public slots: // TODO: do these functions really need to be slots?

/* Exposed functions */
Expand Down
50 changes: 50 additions & 0 deletions python/gui/qgspluginmanagerinterface.sip
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* \class QgsPluginManagerInterface
* \brief Abstract base class to make QgsPluginManager available to plugins.
*/
class QgsPluginManagerInterface : QObject
{
%TypeHeaderCode
#include <qgspluginmanagerinterface.h>
%End

public:

//! Constructor
QgsPluginManagerInterface();

//! Virtual destructor
~QgsPluginManagerInterface();

//! remove metadata of all python plugins from the registry (c++ plugins stay)
virtual void clearPythonPluginMetadata() = 0;

//! add a single plugin to the metadata registry
virtual void addPluginMetadata( QMap<QString,QString> metadata ) = 0;

//! refresh listView model and textView content
virtual void reloadModel() = 0;

//! get given plugin metadata
virtual QMap<QString, QString> * pluginMetadata( QString key ) = 0;

//! clear the repository listWidget
virtual void clearRepositoryList() = 0;

//! add repository to the repository listWidget
virtual void addToRepositoryList( QMap<QString,QString> repository ) = 0;

signals:

//! emitted when the Python Plugin Installer should show the fetching repositories window
void fetchingStillInProgress( );

public slots:

//! show the Plugin Manager window when remote repositories are fetched.
//! Display a progress dialog when fetching.
virtual void showPluginManagerWhenReady( ) = 0;

//! promptly show the Plugin Manager window and optionally open tab tabIndex:
virtual void showPluginManager( int tabIndex = -1 ) = 0;
};
26 changes: 26 additions & 0 deletions python/pyplugin_installer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
SET (QGIS_PLUGININSTALLER_DIR ${QGIS_DATA_DIR}/python/pyplugin_installer)
SET (PYTHON_OUTPUT_DIRECTORY ${QGIS_OUTPUT_DIRECTORY}/python)

SET(PY_PLUGININSTALLER_FILES
__init__.py
installer.py
installer_data.py
installer_gui.py
unzip.py
version_compare.py
)

# FILE(GLOB UI_FILES *.ui)
# PYQT4_WRAP_UI(PYUI_FILES ${UI_FILES})

PYQT4_WRAP_UI(PYUI_FILES
qgsplugininstallerfetchingbase.ui
qgsplugininstallerinstallingbase.ui
qgsplugininstallerpluginerrorbase.ui
qgsplugininstallerrepositorybase.ui
qgsplugininstalleroldreposbase.ui
)

ADD_CUSTOM_TARGET(pyplugin_installer ALL DEPENDS ${PYUI_FILES})

INSTALL(FILES ${PY_PLUGININSTALLER_FILES} ${PYUI_FILES} DESTINATION "${QGIS_PLUGININSTALLER_DIR}")
40 changes: 40 additions & 0 deletions python/pyplugin_installer/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
__init__.py
---------------------
Date : May 2013
Copyright : (C) 2013 by Borys Jurgiel
Email : info at borysjurgiel dot pl
This module is based on former plugin_installer plugin:
Copyright (C) 2007-2008 Matthew Perry
Copyright (C) 2008-2013 Borys Jurgiel
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""

__author__ = 'Borys Jurgiel'
__date__ = 'May 2013'
__copyright__ = '(C) 2013, Borys Jurgiel'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'


# import functions for easier access
import installer
from installer import initPluginInstaller


def instance():
if not installer.pluginInstaller:
installer.initPluginInstaller()
return installer.pluginInstaller
473 changes: 473 additions & 0 deletions python/pyplugin_installer/installer.py

Large diffs are not rendered by default.

759 changes: 759 additions & 0 deletions python/pyplugin_installer/installer_data.py

Large diffs are not rendered by default.

220 changes: 220 additions & 0 deletions python/pyplugin_installer/installer_gui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
# -*- coding:utf-8 -*-
"""
/***************************************************************************
Plugin Installer module
-------------------
Date : May 2013
Copyright : (C) 2013 by Borys Jurgiel
Email : info at borysjurgiel dot pl
This module is based on former plugin_installer plugin:
Copyright (C) 2007-2008 Matthew Perry
Copyright (C) 2008-2013 Borys Jurgiel
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""

import sys
import time

from PyQt4.QtCore import *
from PyQt4.QtGui import *

from qgis.core import QgsApplication, QgsContextHelp

from ui_qgsplugininstallerfetchingbase import Ui_QgsPluginInstallerFetchingDialogBase
from ui_qgsplugininstallerinstallingbase import Ui_QgsPluginInstallerInstallingDialogBase
from ui_qgsplugininstallerrepositorybase import Ui_QgsPluginInstallerRepositoryDetailsDialogBase
from ui_qgsplugininstallerpluginerrorbase import Ui_QgsPluginInstallerPluginErrorDialogBase

from installer_data import *
from unzip import unzip




# --- class QgsPluginInstallerFetchingDialog --------------------------------------------------------------- #
class QgsPluginInstallerFetchingDialog(QDialog, Ui_QgsPluginInstallerFetchingDialogBase):
# ----------------------------------------- #
def __init__(self, parent):
QDialog.__init__(self, parent)
self.setupUi(self)
self.progressBar.setRange(0,len(repositories.allEnabled())*100)
self.itemProgress = {}
self.item = {}
for key in repositories.allEnabled():
self.item[key] = QTreeWidgetItem(self.treeWidget)
self.item[key].setText(0,key)
if repositories.all()[key]["state"] > 1:
self.itemProgress[key] = 100
self.displayState(key,0)
else:
self.itemProgress[key] = 0
self.displayState(key,2)
self.treeWidget.resizeColumnToContents(0)
QObject.connect(repositories, SIGNAL("repositoryFetched(QString)"), self.repositoryFetched)
QObject.connect(repositories, SIGNAL("anythingChanged(QString, int, int)"), self.displayState)


# ----------------------------------------- #
def displayState(self,key,state,state2=None):
messages=[self.tr("Success"),self.tr("Resolving host name..."),self.tr("Connecting..."),self.tr("Host connected. Sending request..."),self.tr("Downloading data..."),self.tr("Idle"),self.tr("Closing connection..."),self.tr("Error")]
message = messages[state]
if state2:
message += " (%s%%)" % state2
self.item[key].setText(1,message)

if state == 4 and state2:
self.itemProgress[key] = state2
totalProgress = sum(self.itemProgress.values())
self.progressBar.setValue(totalProgress)


# ----------------------------------------- #
def repositoryFetched(self, repoName):
self.itemProgress[repoName] = 100
if repositories.all()[repoName]["state"] == 2:
self.displayState(repoName,0)
else:
self.displayState(repoName,7)
if not repositories.fetchingInProgress():
self.close()
# --- /class QgsPluginInstallerFetchingDialog -------------------------------------------------------------- #





# --- class QgsPluginInstallerRepositoryDialog ------------------------------------------------------------- #
class QgsPluginInstallerRepositoryDialog(QDialog, Ui_QgsPluginInstallerRepositoryDetailsDialogBase):
# ----------------------------------------- #
def __init__(self, parent=None):
QDialog.__init__(self, parent)
self.setupUi(self)
self.editURL.setText("http://")
self.connect(self.editName, SIGNAL("textChanged(const QString &)"), self.textChanged)
self.connect(self.editURL, SIGNAL("textChanged(const QString &)"), self.textChanged)
self.textChanged(None)

# ----------------------------------------- #
def textChanged(self, string):
enable = (self.editName.text().count() > 0 and self.editURL.text().count() > 0)
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enable)
# --- /class QgsPluginInstallerRepositoryDialog ------------------------------------------------------------ #





# --- class QgsPluginInstallerInstallingDialog --------------------------------------------------------------- #
class QgsPluginInstallerInstallingDialog(QDialog, Ui_QgsPluginInstallerInstallingDialogBase):
# ----------------------------------------- #
def __init__(self, parent, plugin):
QDialog.__init__(self, parent)
self.setupUi(self)
self.plugin = plugin
self.mResult = QString()
self.progressBar.setRange(0,0)
self.progressBar.setFormat(QString("%p%"))
self.labelName.setText(QString(plugin["name"]))
self.connect(self.buttonBox, SIGNAL("clicked(QAbstractButton*)"), self.abort)

url = QUrl(plugin["download_url"])
path = QString(url.toPercentEncoding(url.path(), "!$&'()*+,;=:/@"))
fileName = plugin["filename"]
tmpDir = QDir.tempPath()
tmpPath = QDir.cleanPath(tmpDir+"/"+fileName)
self.file = QFile(tmpPath)
port = url.port()
if port < 0:
port = 80
self.http = QPHttp(url.host(), port)
self.connect(self.http, SIGNAL("stateChanged ( int )"), self.stateChanged)
self.connect(self.http, SIGNAL("dataReadProgress ( int , int )"), self.readProgress)
self.connect(self.http, SIGNAL("requestFinished (int, bool)"), self.requestFinished)
self.httpGetId = self.http.get(path, self.file)


# ----------------------------------------- #
def result(self):
return self.mResult


# ----------------------------------------- #
def stateChanged(self, state):
messages=[self.tr("Installing..."),self.tr("Resolving host name..."),self.tr("Connecting..."),self.tr("Host connected. Sending request..."),self.tr("Downloading data..."),self.tr("Idle"),self.tr("Closing connection..."),self.tr("Error")]
self.labelState.setText(messages[state])


# ----------------------------------------- #
def readProgress(self, done, total):
self.progressBar.setMaximum(total)
self.progressBar.setValue(done)


# ----------------------------------------- #
def requestFinished(self, requestId, state):
if requestId != self.httpGetId:
return
self.buttonBox.setEnabled(False)
if state:
self.mResult = self.http.errorString()
self.reject()
return
self.file.close()
pluginDir = QFileInfo(QgsApplication.qgisUserDbFilePath()).path() + "/python/plugins"
tmpPath = self.file.fileName()
# make sure that the parent directory exists
if not QDir(pluginDir).exists():
QDir().mkpath(pluginDir)
# if the target directory already exists as a link, remove the link without resolving:
QFile(pluginDir+QString(QDir.separator())+self.plugin["id"]).remove()
try:
unzip(unicode(tmpPath), unicode(pluginDir)) # test extract. If fails, then exception will be raised and no removing occurs
# removing old plugin files if exist
removeDir(QDir.cleanPath(pluginDir+"/"+self.plugin["id"])) # remove old plugin if exists
unzip(unicode(tmpPath), unicode(pluginDir)) # final extract.
except:
self.mResult = self.tr("Failed to unzip the plugin package. Probably it's broken or missing from the repository. You may also want to make sure that you have write permission to the plugin directory:") + "\n" + pluginDir
self.reject()
return
try:
# cleaning: removing the temporary zip file
QFile(tmpPath).remove()
except:
pass
self.close()


# ----------------------------------------- #
def abort(self):
self.http.abort()
self.mResult = self.tr("Aborted by user")
self.reject()
# --- /class QgsPluginInstallerInstallingDialog ------------------------------------------------------------- #





# --- class QgsPluginInstallerPluginErrorDialog -------------------------------------------------------------- #
class QgsPluginInstallerPluginErrorDialog(QDialog, Ui_QgsPluginInstallerPluginErrorDialogBase):
# ----------------------------------------- #
def __init__(self, parent, errorMessage):
QDialog.__init__(self, parent)
self.setupUi(self)
if not errorMessage:
errorMessage = self.tr("no error message received")
self.textBrowser.setText(errorMessage)
# --- /class QgsPluginInstallerPluginErrorDialog ------------------------------------------------------------- #


194 changes: 194 additions & 0 deletions python/pyplugin_installer/qgsplugininstallerfetchingbase.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
<ui version="4.0" >
<author>Borys Jurgiel</author>
<class>QgsPluginInstallerFetchingDialogBase</class>
<widget class="QDialog" name="QgsPluginInstallerFetchingDialogBase" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>521</width>
<height>332</height>
</rect>
</property>
<property name="windowTitle" >
<string>Fetching repositories</string>
</property>
<layout class="QGridLayout" >
<item row="1" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>249</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label1" >
<property name="text" >
<string>Overall progress:</string>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QProgressBar" name="progressBar" >
<property name="value" >
<number>24</number>
</property>
<property name="alignment" >
<set>Qt::AlignHCenter</set>
</property>
<property name="textDirection" >
<enum>QProgressBar::TopToBottom</enum>
</property>
<property name="format" >
<string/>
</property>
</widget>
</item>
<item row="4" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>248</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0" >
<layout class="QHBoxLayout" >
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" >
<size>
<width>140</width>
<height>27</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="buttonSkip" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>180</width>
<height>0</height>
</size>
</property>
<property name="focusPolicy" >
<enum>Qt::NoFocus</enum>
</property>
<property name="text" >
<string>Abort fetching</string>
</property>
<property name="autoDefault" >
<bool>false</bool>
</property>
<property name="default" >
<bool>false</bool>
</property>
<property name="flat" >
<bool>false</bool>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" >
<size>
<width>140</width>
<height>27</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="0" column="0" >
<widget class="QTreeWidget" name="treeWidget" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="horizontalScrollBarPolicy" >
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="showDropIndicator" stdset="0" >
<bool>false</bool>
</property>
<property name="selectionMode" >
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="horizontalScrollMode" >
<enum>QAbstractItemView::ScrollPerItem</enum>
</property>
<property name="rootIsDecorated" >
<bool>false</bool>
</property>
<property name="itemsExpandable" >
<bool>false</bool>
</property>
<column>
<property name="text" >
<string>Repository</string>
</property>
</column>
<column>
<property name="text" >
<string>State</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<connections>
<connection>
<sender>buttonSkip</sender>
<signal>clicked()</signal>
<receiver>QgsPluginInstallerFetchingDialogBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>350</x>
<y>321</y>
</hint>
<hint type="destinationlabel" >
<x>250</x>
<y>76</y>
</hint>
</hints>
</connection>
</connections>
</ui>
118 changes: 118 additions & 0 deletions python/pyplugin_installer/qgsplugininstallerinstallingbase.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<ui version="4.0" >
<author>Borys Jurgiel</author>
<class>QgsPluginInstallerInstallingDialogBase</class>
<widget class="QDialog" name="QgsPluginInstallerInstallingDialogBase" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>520</width>
<height>175</height>
</rect>
</property>
<property name="windowTitle" >
<string>QGIS Python Plugin Installer</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" >
<size>
<width>502</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" >
<layout class="QHBoxLayout" >
<item>
<widget class="QLabel" name="label" >
<property name="text" >
<string>Installing plugin:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelName" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="labelState" >
<property name="text" >
<string>Connecting...</string>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QProgressBar" name="progressBar" >
<property name="maximum" >
<number>100</number>
</property>
<property name="value" >
<number>0</number>
</property>
<property name="alignment" >
<set>Qt::AlignHCenter</set>
</property>
<property name="textDirection" >
<enum>QProgressBar::TopToBottom</enum>
</property>
<property name="format" >
<string/>
</property>
</widget>
</item>
<item row="4" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>502</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0" >
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="focusPolicy" >
<enum>Qt::NoFocus</enum>
</property>
<property name="contextMenuPolicy" >
<enum>Qt::NoContextMenu</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Abort</set>
</property>
<property name="centerButtons" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<connections/>
</ui>
113 changes: 113 additions & 0 deletions python/pyplugin_installer/qgsplugininstalleroldreposbase.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<author>Borys Jurgiel</author>
<class>QgsPluginInstallerOldReposBase</class>
<widget class="QDialog" name="QgsPluginInstallerOldReposBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>601</width>
<height>182</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>480</width>
<height>182</height>
</size>
</property>
<property name="windowTitle">
<string>Plugin Installer</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>The Plugin Installer has detected that your copy of QGIS is configured to use a number of plugin repositories around the world. It was a typical situation in older versions of the program, but from the version 1.5, external plugins are collected in one central Contributed Repository, and all the old repositories are not necessary any more. Do you want to drop them now? If you're unsure what to do, probably you don't need them. However, if you choose to keep them in use, you will be able to remove them manually later.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="butOldReposRemove">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="butOldReposDisable">
<property name="text">
<string>Disable</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="butOldReposKeep">
<property name="text">
<string>Keep</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="butOldReposAsk">
<property name="text">
<string>Ask me later</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<connections/>
</ui>
149 changes: 149 additions & 0 deletions python/pyplugin_installer/qgsplugininstallerpluginerrorbase.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<ui version="4.0" >
<author>Borys Jurgiel</author>
<class>QgsPluginInstallerPluginErrorDialogBase</class>
<widget class="QDialog" name="QgsPluginInstallerPluginErrorDialogBase" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>521</width>
<height>383</height>
</rect>
</property>
<property name="minimumSize" >
<size>
<width>480</width>
<height>300</height>
</size>
</property>
<property name="windowTitle" >
<string>Error loading plugin</string>
</property>
<layout class="QGridLayout" >
<item row="1" column="0" >
<widget class="QLabel" name="label" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>The plugin seems to be invalid or have unfulfilled dependencies. It has been installed, but can't be loaded. If you really need this plugin, you can contact its author or &lt;a href="http://lists.osgeo.org/mailman/listinfo/qgis-user">QGIS users group&lt;/a> and try to solve the problem. If not, you can just uninstall it. Here is the error message below:</string>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
<property name="openExternalLinks" >
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QTextBrowser" name="textBrowser" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="focusPolicy" >
<enum>Qt::NoFocus</enum>
</property>
</widget>
</item>
<item row="3" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>503</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="0" >
<widget class="QLabel" name="label1" >
<property name="frameShape" >
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Plain</enum>
</property>
<property name="text" >
<string>Do you want to uninstall this plugin now? If you're unsure, probably you would like to do this.</string>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0" >
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="standardButtons" >
<set>QDialogButtonBox::No|QDialogButtonBox::NoButton|QDialogButtonBox::Yes</set>
</property>
</widget>
</item>
<item row="0" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>10</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<tabstops>
<tabstop>textBrowser</tabstop>
</tabstops>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QgsPluginInstallerPluginErrorDialogBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>266</x>
<y>428</y>
</hint>
<hint type="destinationlabel" >
<x>266</x>
<y>226</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QgsPluginInstallerPluginErrorDialogBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>266</x>
<y>428</y>
</hint>
<hint type="destinationlabel" >
<x>266</x>
<y>226</y>
</hint>
</hints>
</connection>
</connections>
</ui>
237 changes: 237 additions & 0 deletions python/pyplugin_installer/qgsplugininstallerrepositorybase.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
<ui version="4.0" >
<author>Borys Jurgiel</author>
<class>QgsPluginInstallerRepositoryDetailsDialogBase</class>
<widget class="QDialog" name="QgsPluginInstallerRepositoryDetailsDialogBase" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>522</width>
<height>191</height>
</rect>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle" >
<string>Repository details</string>
</property>
<property name="statusTip" >
<string/>
</property>
<property name="whatsThis" >
<string/>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="label" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>Name:</string>
</property>
</widget>
</item>
<item row="0" column="1" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>16</width>
<height>27</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2" colspan="2" >
<widget class="QLineEdit" name="editName" >
<property name="toolTip" >
<string>Enter a name for the repository</string>
</property>
<property name="whatsThis" >
<string>Enter a name for the repository</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>URL:</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="2" >
<widget class="QLineEdit" name="editURL" >
<property name="toolTip" >
<string>Enter the repository URL, beginning with "http://"</string>
</property>
<property name="whatsThis" >
<string>Enter the repository URL, beginning with "http://"</string>
</property>
<property name="text" >
<string/>
</property>
</widget>
</item>
<item row="2" column="2" >
<widget class="QCheckBox" name="checkBoxEnabled" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip" >
<string>Enable or disable the repository (disabled repositories will be omitted)</string>
</property>
<property name="whatsThis" >
<string>Enable or disable the repository (disabled repositories will be omitted)</string>
</property>
<property name="text" >
<string>Enabled</string>
</property>
<property name="checked" >
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="3" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" >
<size>
<width>351</width>
<height>23</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="2" colspan="2" >
<widget class="QLabel" name="labelInfo" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="palette" >
<palette>
<active>
<colorrole role="WindowText" >
<brush brushstyle="SolidPattern" >
<color alpha="255" >
<red>175</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText" >
<brush brushstyle="SolidPattern" >
<color alpha="255" >
<red>175</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText" >
<brush brushstyle="SolidPattern" >
<color alpha="255" >
<red>128</red>
<green>128</green>
<blue>128</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font" >
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="frameShape" >
<enum>QFrame::NoFrame</enum>
</property>
<property name="text" >
<string/>
</property>
</widget>
</item>
<item row="5" column="0" colspan="4" >
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QgsPluginInstallerRepositoryDetailsDialogBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>257</x>
<y>207</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>216</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QgsPluginInstallerRepositoryDetailsDialogBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>325</x>
<y>207</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>216</y>
</hint>
</hints>
</connection>
</connections>
</ui>
49 changes: 49 additions & 0 deletions python/pyplugin_installer/unzip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# -*- coding:utf-8 -*-
"""
/***************************************************************************
Plugin Installer module
unzip function
-------------------
Date : May 2013
Copyright : (C) 2013 by Borys Jurgiel
Email : info at borysjurgiel dot pl
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""

import zipfile
import os

def unzip(file, targetDir):
""" Creates directory structure and extracts the zip contents to it.
file - the zip file to extract
targetDir - target location
"""

# create destination directory if doesn't exist
if not targetDir.endswith(':') and not os.path.exists(targetDir):
os.makedirs(targetDir)

zf = zipfile.ZipFile(file)
for name in zf.namelist():
# create directory if doesn't exist
localDir = os.path.split(name)[0]
fullDir = os.path.normpath( os.path.join(targetDir, localDir) )
if not os.path.exists(fullDir):
os.makedirs(fullDir)
# extract file
if not name.endswith('/'):
fullPath = os.path.normpath( os.path.join(targetDir, name) )
outfile = open(fullPath, 'wb')
outfile.write(zf.read(name))
outfile.flush()
outfile.close()
145 changes: 145 additions & 0 deletions python/pyplugin_installer/version_compare.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
"""
/***************************************************************************
Plugin Installer module
Plugin version comparision functions
-------------------
Date : 2008-11-24
Copyright : (C) 2008 by Borys Jurgiel
Email : info at borysjurgiel dot pl
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
Here is Python function for comparing version numbers. It's case insensitive
and recognizes all major notations, prefixes (ver. and version), delimiters
(. - and _) and suffixes (alpha, beta, rc, preview and trunk).
Usage: compareVersions(version1, version2)
The function accepts arguments of any type convertable to unicode string
and returns integer value:
0 - the versions are equal
1 - version 1 is higher
2 - version 2 is higher
-----------------------------------------------------------------------------
HOW DOES IT WORK...
First, both arguments are converted to uppercase unicode and stripped of
'VERSION' or 'VER.' prefix. Then they are chopped into a list of particular
numeric and alphabetic elements. The dots, dashes and underlines are recognized
as delimiters. Also numbers and non numbers are separated. See example below:
'Ver 0.03-120_rc7foo' is converted to ['0','03','120','RC','7','FOO']
Then every pair of elements, from left to right, is compared as string
or as number to provide the best result (you know, 11>9 but also '03'>'007').
The comparing stops when one of elements is greater. If comparing achieves
the end of the shorter list and the matter is still unresolved, the longer
list is usually recognized as higher, except following suffixes:
ALPHA, BETA, RC, PREVIEW and TRUNK which make the version number lower.
"""

# ------------------------------------------------------------------------ #
def normalizeVersion(s):
""" remove possible prefix from given string and convert to uppercase """
prefixes = ['VERSION','VER.','VER','V.','V','REVISION','REV.','REV','R.','R']
if not s:
return unicode()
s = unicode(s).upper()
for i in prefixes:
if s[:len(i)] == i:
s = s.replace(i,'')
s = s.strip()
return s


# ------------------------------------------------------------------------ #
def classifyCharacter(c):
""" return 0 for delimiter, 1 for digit and 2 for alphabetic character """
if c in [".","-","_"," "]:
return 0
if c.isdigit():
return 1
else:
return 2


# ------------------------------------------------------------------------ #
def chopString(s):
""" convert string to list of numbers and words """
l = [s[0]]
for i in range(1,len(s)):
if classifyCharacter(s[i]) == 0:
pass
elif classifyCharacter(s[i]) == classifyCharacter(s[i-1]):
l[len(l)-1] += s[i]
else:
l += [s[i]]
return l


# ------------------------------------------------------------------------ #
def compareElements(s1,s2):
""" compare two particular elements """
# check if the matter is easy solvable:
if s1 == s2:
return 0
# try to compare as numeric values (but only if the first character is not 0):
if s1 and s2 and s1.isnumeric() and s2.isnumeric() and s1[0] != '0' and s2[0] != '0':
if float(s1) == float(s2):
return 0
elif float(s1) > float(s2):
return 1
else:
return 2
# if the strings aren't numeric or start from 0, compare them as a strings:
# but first, set ALPHA < BETA < PREVIEW < RC < TRUNK < [NOTHING] < [ANYTHING_ELSE]
if not s1 in ['ALPHA','BETA','PREVIEW','RC','TRUNK']:
s1 = 'Z' + s1
if not s2 in ['ALPHA','BETA','PREVIEW','RC','TRUNK']:
s2 = 'Z' + s2
# the final test:
if s1 > s2:
return 1
else:
return 2


# ------------------------------------------------------------------------ #
def compareVersions(a,b):
""" Compare two version numbers. Return 0 if a==b or error, 1 if a<b and 2 if b>a """
if not a or not b:
return 0
a = normalizeVersion(a)
b = normalizeVersion(b)
if a == b:
return 0
# convert the strings to the lists
v1 = chopString(a)
v2 = chopString(b)
# set the shorter string as a base
l = len(v1)
if l > len(v2):
l = len(v2)
# try to determine within the common length
for i in range(l):
if compareElements(v1[i],v2[i]):
return compareElements(v1[i],v2[i])
# if the lists are identical till the end of the shorther string, try to compare the odd tail
#with the simple space (because the 'alpha', 'beta', 'preview' and 'rc' are LESS then nothing)
if len(v1) > l:
return compareElements(v1[l],u' ')
if len(v2) > l:
return compareElements(u' ',v2[l])
# if everything else fails...
if a > b:
return 1
else:
return 2
15 changes: 10 additions & 5 deletions src/app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ SET(QGIS_APP_SRCS
qgsmaptoolsplitfeatures.cpp
qgsmaptoolsvgannotation.cpp
qgsmaptooltextannotation.cpp
qgsmaptoolvertexedit.cpp
qgsmaptoolvertexedit.cpp

nodetool/qgsmaptoolnodetool.cpp
nodetool/qgsselectedfeature.cpp
Expand All @@ -91,8 +91,6 @@ SET(QGIS_APP_SRCS
qgsoptions.cpp
#qgspastetransformations.cpp
qgspointrotationitem.cpp
qgspluginitem.cpp
qgspluginmanager.cpp
qgspluginmetadata.cpp
qgspluginregistry.cpp
qgsprojectlayergroupdialog.cpp
Expand Down Expand Up @@ -150,6 +148,10 @@ SET(QGIS_APP_SRCS
openstreetmap/qgsosmimportdialog.cpp
openstreetmap/qgsosmexportdialog.cpp

pluginmanager/qgspluginmanager.cpp
pluginmanager/qgsapppluginmanagerinterface.cpp
pluginmanager/qgspluginsortfilterproxymodel.cpp

qgsnewspatialitelayerdialog.cpp
)

Expand Down Expand Up @@ -233,7 +235,6 @@ SET (QGIS_APP_MOC_HDRS
qgsmergeattributesdialog.h
qgsoptions.h
#qgspastetransformations.h
qgspluginmanager.h
qgsprojectlayergroupdialog.h
qgsprojectproperties.h
qgsrastercalcdialog.h
Expand Down Expand Up @@ -279,6 +280,10 @@ SET (QGIS_APP_MOC_HDRS
openstreetmap/qgsosmimportdialog.h
openstreetmap/qgsosmexportdialog.h

pluginmanager/qgspluginmanager.h
pluginmanager/qgsapppluginmanagerinterface.h
pluginmanager/qgspluginsortfilterproxymodel.h

qgsnewspatialitelayerdialog.h
)

Expand Down Expand Up @@ -395,7 +400,7 @@ IF(PEDANTIC)
ENDIF(PEDANTIC)

INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_SOURCE_DIR} composer legend attributetable
${CMAKE_CURRENT_SOURCE_DIR} composer legend pluginmanager
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/../ui
${QWT_INCLUDE_DIR}
Expand Down
29 changes: 29 additions & 0 deletions src/app/pluginmanager/metadata
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
PLUGIN METADATA TAGS
=======================================================
id the key, usually library base name
name
description
icon path to installed or available icon
category will be removed?
tags comma separated, spaces allowed
changelog may be multiline
author_name
author_email
homepage url
tracker url
code_repository url
version_installed
library cpp: path to the installed library | Python: module name
pythonic is plugin pythonic or cpp?
readonly is core plugin?
status not installed | installed | upgradeable | orphan | new | newer *
error NULL | broken | incompatible | dependent
error_details
experimental choosen version status
version_available
zip_repository the remote repository id
download_url
filename the zip file name
downloads number of dowloads
average_vote
rating_votes number of votes
102 changes: 102 additions & 0 deletions src/app/pluginmanager/qgsapppluginmanagerinterface.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/***************************************************************************
qgsapppluginmanagerinterface.cpp
--------------------------------------
Date : 15-May-2013
Copyright : (C) 2013 by Borys Jurgiel
Email : info at borysjurgiel dot pl
****************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsapppluginmanagerinterface.h"
#include <qgslogger.h>


QgsAppPluginManagerInterface::QgsAppPluginManagerInterface( QgsPluginManager * pluginManager )
: mPluginManager( pluginManager )
{
}


QgsAppPluginManagerInterface::~QgsAppPluginManagerInterface()
{
}


//! show the Plugin Manager window when remote repositories are fetched.
//! Display a progress dialog when fetching.
void QgsAppPluginManagerInterface::showPluginManagerWhenReady( )
{
}


//! promptly show the Plugin Manager window and optionally open tab tabIndex:
void QgsAppPluginManagerInterface::showPluginManager( int tabIndex )
{
mPluginManager->getCppPluginDescriptions();
mPluginManager->reloadModelData();

//! switch to tab, if specified ( -1 means not specified )
if ( tabIndex > -1 )
{
mPluginManager->selectTabItem( tabIndex );
}

mPluginManager->exec();
}


//! remove metadata of all python plugins from the registry (c++ plugins stay)
void QgsAppPluginManagerInterface::clearPythonPluginMetadata()
{
mPluginManager->clearPythonPluginMetadata();
}


//! add a single plugin to the metadata registry
void QgsAppPluginManagerInterface::addPluginMetadata( QMap<QString,QString> metadata )
{
if ( metadata.isEmpty() || !metadata.contains("id") )
{
QgsDebugMsg( "Warning: incomplete metadata" );
return;
}
mPluginManager->addPluginMetadata( metadata.value("id"), metadata );
}


//! refresh listView model and textView content
void QgsAppPluginManagerInterface::reloadModel()
{
mPluginManager->reloadModelData();
}




//! get given plugin metadata
QMap<QString,QString> * QgsAppPluginManagerInterface::pluginMetadata( QString key )
{
return mPluginManager->pluginMetadata( key );
}


//! clear the repository listWidget
void QgsAppPluginManagerInterface::clearRepositoryList()
{
mPluginManager->clearRepositoryList();
}


//! add repository to the repository listWidget
void QgsAppPluginManagerInterface::addToRepositoryList( QMap<QString,QString> repository )
{
mPluginManager->addToRepositoryList( repository );
}

72 changes: 72 additions & 0 deletions src/app/pluginmanager/qgsapppluginmanagerinterface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/***************************************************************************
qgsapppluginmanagerinterface.h
--------------------------------------
Date : 15-May-2013
Copyright : (C) 2013 by Borys Jurgiel
Email : info at borysjurgiel dot pl
****************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSPLUGINMANAGERAPPIFACE_H
#define QGSPLUGINMANAGERAPPIFACE_H

#include "qgspluginmanagerinterface.h"
#include "qgspluginmanager.h"

/** \ingroup gui
* QgsPluginManagerInterface
* Abstract base class to make QgsPluginManager available to plugins.
*/
class QgsAppPluginManagerInterface : public QgsPluginManagerInterface
{
Q_OBJECT

public:

//! Constructor
explicit QgsAppPluginManagerInterface( QgsPluginManager * pluginManager );

//! Destructor
~QgsAppPluginManagerInterface();

//! remove metadata of all python plugins from the registry (c++ plugins stay)
void clearPythonPluginMetadata();

//! add a single plugin to the metadata registry
void addPluginMetadata( QMap<QString,QString> metadata );

//! refresh listView model and textView content
void reloadModel();

//! get given plugin metadata
QMap<QString, QString> * pluginMetadata( QString key );

//! clear the repository listWidget
void clearRepositoryList();

//! add repository to the repository listWidget
void addToRepositoryList( QMap<QString,QString> repository );

public slots:

//! show the Plugin Manager window when remote repositories are fetched.
//! Display a progress dialog when fetching.
void showPluginManagerWhenReady( );

//! promptly show the Plugin Manager window and optionally open tab tabIndex:
void showPluginManager( int tabIndex = -1 );

private:

//! Pointer to QgsPluginManager object
QgsPluginManager *mPluginManager;
};

#endif //QGSPLUGINMANAGERAPPIFACE_H
1,449 changes: 1,449 additions & 0 deletions src/app/pluginmanager/qgspluginmanager.cpp

Large diffs are not rendered by default.

182 changes: 182 additions & 0 deletions src/app/pluginmanager/qgspluginmanager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/***************************************************************************
qgspluginmanager.h
Plugin manager for loading/unloading QGIS plugins
-------------------
begin : 2004-02-12
copyright : (C) 2004 by Gary E.Sherman
email : sherman at mrcc.com
***************************************************************************/

/***************************************************************************
* *
// * This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSPLUGINMANAGER_H
#define QGSPLUGINMANAGER_H
#include <vector>
#include <QMap>
#include <QString>
#include <QStandardItemModel>
#include <QStandardItem>
#include <QHeaderView>
#include "ui_qgspluginmanagerbase.h"
#include "qgsoptionsdialogbase.h"
#include "qgisgui.h"
#include "qgscontexthelp.h"
#include "qgspythonutils.h"
#include "qgspluginsortfilterproxymodel.h"



/*!
* \brief Plugin manager for loading/unloading plugins
@author Gary Sherman
*/
class QgsPluginManager : public QgsOptionsDialogBase, private Ui::QgsPluginManagerBase
{
Q_OBJECT
public:
//! Constructor
QgsPluginManager( QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags );
//! Destructor
~QgsPluginManager();

//! Save pointer for python utils - necessary for unloading Python plugins
void setPythonUtils( QgsPythonUtils* pythonUtils );

//! Load selected plugin
void loadPlugin( QString id );
//! Unload unselected plugin
void unloadPlugin( QString id );
//! Get description of C++ plugins (name, etc)
void getCppPluginDescriptions();

//! Repopulate the plugin list model
void reloadModelData();
//! Populate the html browser widget with plugin details
void showPluginDetails( QStandardItem * item );

//! Remove python plugins from the metadata registry (c++ plugins stay)
void clearPythonPluginMetadata();

//! Add a single plugin to the map of plugin metadata
void addPluginMetadata( QString key, QMap<QString,QString> metadata );

//! Get metadata of given plugin
QMap<QString,QString> * pluginMetadata( QString key );

//! Switch to one of vertical tabs by API
void selectTabItem( int idx );

//! Clear the repository listWidget
void clearRepositoryList();

//! Add repository to the repository listWidget
void addToRepositoryList( QMap<QString,QString> repository );

// // //! Set vwPlugins table GUI
// // void setTable();
// // //! Get description of Pythin plugins (does nothing when python is disabled)
// // void getPythonPluginDescriptions();
// // //! Resize columns to contents
// // void resizeColumnsToContents();
// // //! Sort model by column ascending
// // void sortModel( int );
// // //! Check whether plugin installer is available (and tries to load it if it's disabled)
// // bool checkForPluginInstaller();

public slots:
//! Load selected plugins and close the dialog (called when the "Close" button clicked)
void reject();
//! Update stacket widget (called from the vertical list item)
void setCurrentTab( int idx );
//! Updates current tab tile of according to current filters
void updateTabTitle();
//! Handle plugin selection
void currentPluginChanged( const QModelIndex & theIndex );
//! Load/unload plugin when checkbox state changed
void pluginItemChanged( QStandardItem * item );
//! Display details of inactive item too
void on_vwPlugins_clicked( const QModelIndex & );
//! Disable/enable plugin after double click
void on_vwPlugins_doubleClicked( const QModelIndex & index );
//! Update the filter when user changes the filter expression
void on_leFilter_textChanged( QString theText );
//! Set filter mode to filter by name
void on_rbFilterNames_toggled( bool checked );
//! Set filter mode to filter by description
void on_rbFilterDescriptions_toggled( bool checked );
//! Set filter mode to filter by tags
void on_rbFilterTags_toggled( bool checked );
//! Set filter mode to filter by autor
void on_rbFilterAuthors_toggled( bool checked );
//! Upgrade all upgradeable plugins
void on_buttonUpgradeAll_clicked( );
//! Install selected plugin
void on_buttonInstall_clicked( );
//! Uninstall selected plugin
void on_buttonUninstall_clicked( );

//! Enable/disable buttons according to selected repository
void on_treeRepositories_itemSelectionChanged( );
//! Edit selected repository
void on_treeRepositories_doubleClicked( QModelIndex );
//! Define new repository connection
void on_buttonAddRep_clicked( );
//! Edit selected repository connection
void on_buttonEditRep_clicked( );
//! Delete selected repository connection
void on_buttonDeleteRep_clicked( );
//! Refresh all repositories
void on_buttonRefreshRepos_clicked( );

//! Reload plugin metadata registry after allowing/disallowing experimental plugins
void on_ckbExperimental_toggled( bool state );

//! Open help browser
void on_buttonBox_helpRequested( ) { QgsContextHelp::run( metaObject()->className() ); }

// // // //! Select all plugins by setting their checkbox on
// // // void selectAll();
// // // //! Clear all selections by clearing the plugins checkbox
// // // void clearAll();
// // // //! Show the plugin installer
// // // void showPluginInstaller();

// // // //! query the metadata registry about some frequently used state questions
// // // bool pluginState( QString key, QString question );

//! Overwrite QgsOptionsDialogBase method to prevent changing the tab list from the stacked widget
void optionsStackedWidget_CurrentChanged( int indx ) { Q_UNUSED( indx ) }

private:

//! Return true if given plugin is currently present in QgsPluginRegistry
bool isPluginLoaded( QString key );

//! Return true if there are upgradeable plugins in the registry
bool hasUpgradeablePlugins( );

//! Return true if there are new plugins in the registry
bool hasNewPlugins( );

//! Return true if there are invalid plugins in the registry
bool hasInvalidPlugins( );

QStandardItemModel *mModelPlugins;
QgsPluginSortFilterProxyModel * mModelProxy;

QgsPythonUtils* mPythonUtils;

QMap< QString, QMap< QString,QString > > mPlugins;

QString mCurrentlyDisplayedPlugin;

QList<int> checkingOnStartIntervals;
};

#endif
116 changes: 116 additions & 0 deletions src/app/pluginmanager/qgspluginsortfilterproxymodel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/***************************************************************************
qgspluginsortfilterproxymodel.cpp
--------------------------------------
Date : 20-May-2013
Copyright : (C) 2013 by Borys Jurgiel
Email : info at borysjurgiel dot pl
****************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgspluginsortfilterproxymodel.h"
#include "qgslogger.h"

QgsPluginSortFilterProxyModel::QgsPluginSortFilterProxyModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
}




bool QgsPluginSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QModelIndex inx = sourceModel()->index(sourceRow, 0, sourceParent);

return ( filterByStatus( inx ) && sourceModel()->data( inx, filterRole() ).toString().contains( filterRegExp() ) );
}




void QgsPluginSortFilterProxyModel::setAcceptedStatuses( QStringList statuses)
{
mAcceptedStatuses = statuses;
invalidateFilter();
}




bool QgsPluginSortFilterProxyModel::filterByStatus( QModelIndex &index ) const
{
if ( mAcceptedStatuses.contains( "invalid" )
&& sourceModel()->data(index, PLUGIN_ERROR_ROLE).toString().isEmpty() )
{
// Don't accept if the "invalid" filter is set and the plugin is ok
return false;
}

if ( ! mAcceptedStatuses.isEmpty()
&& ! mAcceptedStatuses.contains( "invalid" )
&& ! mAcceptedStatuses.contains( sourceModel()->data(index, PLUGIN_STATUS_ROLE).toString() ) )
{
// Don't accept if the status doesn't match
return false;
}

// Otherwise, let the item go.
return true;
}




int QgsPluginSortFilterProxyModel::countWithCurrentStatus( )
{
int result = 0;
for (int i=0; i < sourceModel()->rowCount(); ++i)
{
QModelIndex idx = sourceModel()->index(i, 0);
if ( filterByStatus( idx ) )
{
result++ ;
}
}
return result;
}




void QgsPluginSortFilterProxyModel::sortPluginsByName( )
{
sort( 0, Qt::AscendingOrder );
setSortRole( Qt::DisplayRole );
}

void QgsPluginSortFilterProxyModel::sortPluginsByDownloads( )
{
sort( 0, Qt::DescendingOrder );
setSortRole( PLUGIN_DOWNLOADS_ROLE );
}

void QgsPluginSortFilterProxyModel::sortPluginsByVote( )
{
sort( 0, Qt::DescendingOrder );
setSortRole( PLUGIN_VOTE_ROLE );
}

void QgsPluginSortFilterProxyModel::sortPluginsByStatus( )
{
sort( 0, Qt::DescendingOrder );
setSortRole( PLUGIN_STATUS_ROLE );
}

void QgsPluginSortFilterProxyModel::sortPluginsByRepository( )
{
sort( 0, Qt::DescendingOrder );
setSortRole( PLUGIN_REPOSITORY_ROLE );
}
69 changes: 69 additions & 0 deletions src/app/pluginmanager/qgspluginsortfilterproxymodel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/***************************************************************************
qgspluginsortfilterproxymodel.h
--------------------------------------
Date : 20-May-2013
Copyright : (C) 2013 by Borys Jurgiel
Email : info at borysjurgiel dot pl
****************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSPLUGINSORTFILTERPROXYMODEL_H
#define QGSPLUGINSORTFILTERPROXYMODEL_H

#include <QSortFilterProxyModel>
#include <QStringList>
// #include <QString>
// #include <QMap>

const int PLUGIN_BASE_NAME_ROLE = Qt::UserRole + 1;
const int PLUGIN_DESCRIPTION_ROLE = Qt::UserRole + 2; // for filtering
const int PLUGIN_AUTHOR_ROLE = Qt::UserRole + 3; // for filtering
const int PLUGIN_TAGS_ROLE = Qt::UserRole + 4; // for filtering
const int PLUGIN_ERROR_ROLE = Qt::UserRole + 6; // for filtering
const int PLUGIN_STATUS_ROLE = Qt::UserRole + 5; // for filtering and sorting
const int PLUGIN_DOWNLOADS_ROLE = Qt::UserRole + 7; // for sorting
const int PLUGIN_VOTE_ROLE = Qt::UserRole + 8; // for sorting
const int PLUGIN_REPOSITORY_ROLE = Qt::UserRole + 9; // for sorting


/*!
* \brief Proxy model for filtering and sorting items in Plugin Manager
*/
class QgsPluginSortFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT

public:
QgsPluginSortFilterProxyModel(QObject *parent = 0);

//! (Re)configire the status filter
void setAcceptedStatuses( QStringList statuses );

//! Return number of item with status filter matching (no other filters are considered)
int countWithCurrentStatus( );

public slots:
void sortPluginsByName( );
void sortPluginsByDownloads( );
void sortPluginsByVote( );
void sortPluginsByStatus( );
void sortPluginsByRepository( );

protected:
//! Filter by status: this method is used in both filterAcceptsRow and countWithCurrentStatus.
bool filterByStatus( QModelIndex &index ) const;
//! The main filter method
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;

private:
QStringList mAcceptedStatuses;
};

#endif
49 changes: 27 additions & 22 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,9 @@
#include "qgsnewvectorlayerdialog.h"
#include "qgsoptions.h"
// #include "qgspastetransformations.h"
#include "qgspluginitem.h"
#include "qgspluginlayer.h"
#include "qgspluginlayerregistry.h"
#include "qgspluginmanager.h"
#include "qgspluginmetadata.h"
#include "qgspluginregistry.h"
#include "qgspoint.h"
#include "qgshandlebadlayers.h"
Expand Down Expand Up @@ -529,6 +527,9 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, QWidget * parent,
mSaveRollbackInProgress = false;
activateDeactivateLayerRelatedActions( NULL );

// initialize the plugin manager
mPluginManager = new QgsPluginManager( this );

addDockWidget( Qt::LeftDockWidgetArea, mUndoWidget );
mUndoWidget->hide();

Expand Down Expand Up @@ -626,6 +627,15 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, QWidget * parent,
}
}

if ( mPythonUtils && mPythonUtils->isEnabled() )
{
// pass the python utils to plugin manager
mPluginManager -> setPythonUtils( mPythonUtils );
// initialize the plugin installer to start fetching repositories in background
QgsPythonRunner::run( "import pyplugin_installer");
QgsPythonRunner::run( "pyplugin_installer.initPluginInstaller()");
}

mSplash->showMessage( tr( "Initializing file filters" ), Qt::AlignHCenter | Qt::AlignBottom );
qApp->processEvents();
// now build vector file filter
Expand Down Expand Up @@ -2029,6 +2039,12 @@ QgsLegend *QgisApp::legend()
return mMapLegend;
}

QgsPluginManager *QgisApp::pluginManager()
{
Q_ASSERT( mPluginManager );
return mPluginManager;
}

QgsMapCanvas *QgisApp::mapCanvas()
{
Q_ASSERT( mMapCanvas );
Expand Down Expand Up @@ -6280,27 +6296,16 @@ void QgisApp::zoomToLayerExtent()

void QgisApp::showPluginManager()
{
QgsPluginManager *pm = new QgsPluginManager( mPythonUtils, this );
pm->resizeColumnsToContents();
if ( pm->exec() )

if ( mPythonUtils && mPythonUtils->isEnabled() )
{
QgsPluginRegistry* pRegistry = QgsPluginRegistry::instance();
// load selected plugins
std::vector < QgsPluginItem > pi = pm->getSelectedPlugins();
std::vector < QgsPluginItem >::iterator it = pi.begin();
while ( it != pi.end() )
{
QgsPluginItem plugin = *it;
if ( plugin.isPython() )
{
pRegistry->loadPythonPlugin( plugin.fullPath() );
}
else
{
pRegistry->loadCppPlugin( plugin.fullPath() );
}
it++;
}
// A detour to the plugin manager via the plugin installer to test if fetching repositories is over.
QgsPythonRunner::run( "pyplugin_installer.instance().showPluginManagerWhenReady()");
}
else
{
// Call the pluginManagerInterface directly
mQgisInterface->pluginManagerInterface()->showPluginManager();
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/app/qgisapp.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class QAuthenticator;

class QgsBrowserDockWidget;
class QgsSnappingDialog;
class QgsPluginManager;
class QgsGPSInformationWidget;

class QgsDecorationItem;
Expand All @@ -91,6 +92,7 @@ class QgsTileScaleWidget;
#include "qgspoint.h"
#include "qgsrasterlayer.h"
#include "qgssnappingdialog.h"
#include "qgspluginmanager.h"

#include "ui_qgisapp.h"

Expand Down Expand Up @@ -407,6 +409,9 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
//! returns pointer to map legend
QgsLegend *legend();

//! returns pointer to plugin manager
QgsPluginManager *pluginManager();

/** Return vector layers in edit mode
* @param modified whether to return only layers that have been modified
* @returns list of layers in legend order, or empty list
Expand Down Expand Up @@ -1432,6 +1437,8 @@ class QgisApp : public QMainWindow, private Ui::MainWindow

QgsSnappingDialog* mSnappingDialog;

QgsPluginManager* mPluginManager;

//! Persistent tile scale slider
QgsTileScaleWidget * mpTileScaleWidget;

Expand Down
9 changes: 8 additions & 1 deletion src/app/qgisappinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@
#include "qgsattributeaction.h"
#include "qgsattributetabledialog.h"


QgisAppInterface::QgisAppInterface( QgisApp * _qgis )
: qgis( _qgis ),
legendIface( _qgis->legend() )
legendIface( _qgis->legend() ),
pluginManagerIface( _qgis->pluginManager() )
{
// connect signals
connect( qgis->legend(), SIGNAL( currentLayerChanged( QgsMapLayer * ) ),
Expand Down Expand Up @@ -73,6 +75,11 @@ QgsLegendInterface* QgisAppInterface::legendInterface()
return &legendIface;
}

QgsPluginManagerInterface* QgisAppInterface::pluginManagerInterface()
{
return &pluginManagerIface;
}

void QgisAppInterface::zoomFull()
{
qgis->zoomFull();
Expand Down
6 changes: 6 additions & 0 deletions src/app/qgisappinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "qgisinterface.h"
#include "qgsapplegendinterface.h"
#include "qgsapppluginmanagerinterface.h"

class QgisApp;

Expand Down Expand Up @@ -49,6 +50,8 @@ class QgisAppInterface : public QgisInterface

QgsLegendInterface* legendInterface();

QgsPluginManagerInterface* pluginManagerInterface();

/* Exposed functions */

//! Zoom map to full extent
Expand Down Expand Up @@ -474,6 +477,9 @@ class QgisAppInterface : public QgisInterface

//! Pointer to the LegendInterface object
QgsAppLegendInterface legendIface;

//! Pointer to the PluginManagerInterface object
QgsAppPluginManagerInterface pluginManagerIface;
};

#ifdef _MSC_VER
Expand Down
57 changes: 0 additions & 57 deletions src/app/qgspluginitem.cpp

This file was deleted.

48 changes: 0 additions & 48 deletions src/app/qgspluginitem.h

This file was deleted.

641 changes: 0 additions & 641 deletions src/app/qgspluginmanager.cpp

This file was deleted.

80 changes: 0 additions & 80 deletions src/app/qgspluginmanager.h

This file was deleted.

40 changes: 40 additions & 0 deletions src/app/qgspluginregistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,46 @@ void QgsPluginRegistry::loadCppPlugin( QString theFullPathName )
}
}


void QgsPluginRegistry::unloadPythonPlugin( QString packageName )
{
if ( !mPythonUtils || !mPythonUtils->isEnabled() )
{
QgsMessageLog::logMessage( QObject::tr( "Python is not enabled in QGIS." ), QObject::tr( "Plugins" ) );
return;
}

if ( isLoaded( packageName ) )
{
mPythonUtils->unloadPlugin( packageName );
// add to settings
QSettings settings;
settings.setValue( "/PythonPlugins/" + packageName, false );
QgsDebugMsg( "Python plugin successfully unloaded: " + packageName );
}
}


void QgsPluginRegistry::unloadCppPlugin( QString theFullPathName )
{
QString baseName = QFileInfo( theFullPathName ).baseName();
// first check to see if it's loaded
if ( isLoaded( baseName ) )
{
QgisPlugin * pluginInstance = plugin( baseName );
if ( pluginInstance )
{
pluginInstance->unload();
}
QSettings settings;
settings.setValue( "/Plugins/" + baseName, false );
// remove the plugin from the registry
removePlugin( baseName );
QgsDebugMsg( "Cpp plugin successfully unloaded: " + baseName);
}
}


//overloaded version of the next method that will load from multiple directories not just one
void QgsPluginRegistry::restoreSessionPlugins( QStringList thePluginDirList )
{
Expand Down
5 changes: 5 additions & 0 deletions src/app/qgspluginregistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ class QgsPluginRegistry
//! Python plugin loader
void loadPythonPlugin( QString packageName );

//! C++ plugin unloader
void unloadCppPlugin( QString theFullPathName );
//! Python plugin unloader
void unloadPythonPlugin( QString packageName );

//! Overloaded version of the next method that will load from multiple directories not just one
void restoreSessionPlugins( QStringList thePluginDirList );
//! Load any plugins used in the last qgis session
Expand Down
2 changes: 2 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ qgsattributeeditor.cpp
qgsattributedialog.cpp
qgsbusyindicatordialog.cpp
qgslegendinterface.cpp
qgspluginmanagerinterface.cpp
qgsblendmodecombobox.cpp
qgscharacterselectdialog.cpp
qgscolorbutton.cpp
Expand Down Expand Up @@ -187,6 +188,7 @@ qgsdetaileditemdelegate.h
qgsdetaileditemwidget.h
qgsdialog.h
qgslegendinterface.h
qgspluginmanagerinterface.h
qgisinterface.h
qgsencodingfiledialog.h
qgserrordialog.h
Expand Down
3 changes: 3 additions & 0 deletions src/gui/qgisinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class QgsMapCanvas;
class QgsRasterLayer;
class QgsVectorLayer;
class QgsLegendInterface;
class QgsPluginManagerInterface;
class QgsFeature;
class QgsMessageBar;

Expand Down Expand Up @@ -75,6 +76,8 @@ class GUI_EXPORT QgisInterface : public QObject
*/
virtual QgsLegendInterface* legendInterface() = 0;

virtual QgsPluginManagerInterface* pluginManagerInterface() = 0;

public slots: // TODO: do these functions really need to be slots?

/* Exposed functions */
Expand Down
26 changes: 26 additions & 0 deletions src/gui/qgspluginmanagerinterface.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/***************************************************************************
qgspluginmanagerinterface.cpp
--------------------------------------
Date : 15-May-2013
Copyright : (C) 2013 by Borys Jurgiel
Email : info at borysjurgiel dot pl
****************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgspluginmanagerinterface.h"

QgsPluginManagerInterface::QgsPluginManagerInterface()
{
}

QgsPluginManagerInterface::~QgsPluginManagerInterface()
{
}

70 changes: 70 additions & 0 deletions src/gui/qgspluginmanagerinterface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/***************************************************************************
qgspluginmanagerinterface.h
--------------------------------------
Date : 15-May-2013
Copyright : (C) 2013 by Borys Jurgiel
Email : info at borysjurgiel dot pl
****************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSPLUGINMANAGERINTERFACE_H
#define QGSPLUGINMANAGERINTERFACE_H

#include <QObject>
#include <QString>
#include <QMap>

class GUI_EXPORT QgsPluginManagerInterface : public QObject
{
Q_OBJECT

public:

//! Constructor
QgsPluginManagerInterface();

//! Virtual destructor
virtual ~QgsPluginManagerInterface();

//! remove metadata of all python plugins from the registry (c++ plugins stay)
virtual void clearPythonPluginMetadata() = 0;

//! add a single plugin to the metadata registry
virtual void addPluginMetadata( QMap<QString,QString> metadata ) = 0;

//! refresh listView model and textView content
virtual void reloadModel() = 0;

//! get given plugin metadata
virtual QMap<QString, QString> * pluginMetadata( QString key ) = 0;

//! clear the repository listWidget
virtual void clearRepositoryList() = 0;

//! add repository to the repository listWidget
virtual void addToRepositoryList( QMap<QString,QString> repository ) = 0;

signals:

//! emitted when the Python Plugin Installer should show the fetching repositories window
void fetchingStillInProgress( );

public slots:

//! show the Plugin Manager window when remote repositories are fetched.
//! Display a progress dialog when fetching.
virtual void showPluginManagerWhenReady( ) = 0;

//! promptly show the Plugin Manager window and optionally open tab tabIndex:
virtual void showPluginManager( int tabIndex = -1 ) = 0;

};

#endif
938 changes: 870 additions & 68 deletions src/ui/qgspluginmanagerbase.ui

Large diffs are not rendered by default.