Merged in Borys's new plugin installer

git-svn-id: http://svn.osgeo.org/qgis/trunk@9293 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
timlinux 2008-09-10 20:26:08 +00:00
parent d049698222
commit 47a02a106f
22 changed files with 3616 additions and 23 deletions

View File

@ -10,5 +10,22 @@ qgis_plugins.py
resources.py
repository_ui.py
repository_dialog.py
qgis-icon.png
installingbase.ui
fetchingbase.py
guibase.py
repositorybase.py
plugin_installer.png
unzip.py
installer_gui.py
installingbase.py
pluginerrorbase.ui
installer_data.py
repoConnected.png
guibase.ui
pluginerrorbase.py
repositorybase.ui
resources_rc.py
repoDisabled.png
)
INSTALL(FILES ${INSTALLER_FILES} DESTINATION ${QGIS_DATA_DIR}/python/plugins/plugin_installer)

View File

@ -1,4 +1,6 @@
Copyright (c) 2007 Matthew T. Perry
Copyright (c) 2008 Borys Jurgiel
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View File

@ -1,5 +1,6 @@
"""
Copyright (C) 2008 Matthew Perry
Copyright (C) 2008 Borys Jurgiel
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
@ -10,15 +11,17 @@ Copyright (C) 2008 Matthew Perry
***************************************************************************/
"""
def name():
return "Plugin installer"
return "Plugin Installer"
def description():
return "Downloads and installs QGIS python plugins"
def author_name():
return "perrygeo, borysiasty"
def version():
return "Version 0.02"
return "Version 0.05.6"
def classFactory(iface):
# load TestPlugin class from file testplugin.py
from installer_plugin import InstallerPlugin
return InstallerPlugin(iface)
return InstallerPlugin(iface)

View File

@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'fetchingbase.ui'
#
# Created: Sun Sep 7 16:22:19 2008
# by: PyQt4 UI code generator 4.3
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_QgsPluginInstallerFetchingDialog(object):
def setupUi(self, QgsPluginInstallerFetchingDialog):
QgsPluginInstallerFetchingDialog.setObjectName("QgsPluginInstallerFetchingDialog")
QgsPluginInstallerFetchingDialog.resize(QtCore.QSize(QtCore.QRect(0,0,521,332).size()).expandedTo(QgsPluginInstallerFetchingDialog.minimumSizeHint()))
QgsPluginInstallerFetchingDialog.setWindowIcon(QtGui.QIcon(":/plugins/installer/qgis-icon.png"))
self.gridlayout = QtGui.QGridLayout(QgsPluginInstallerFetchingDialog)
self.gridlayout.setObjectName("gridlayout")
spacerItem = QtGui.QSpacerItem(249,10,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Fixed)
self.gridlayout.addItem(spacerItem,1,0,1,1)
self.label1 = QtGui.QLabel(QgsPluginInstallerFetchingDialog)
self.label1.setObjectName("label1")
self.gridlayout.addWidget(self.label1,2,0,1,1)
self.progressBar = QtGui.QProgressBar(QgsPluginInstallerFetchingDialog)
self.progressBar.setProperty("value",QtCore.QVariant(24))
self.progressBar.setAlignment(QtCore.Qt.AlignHCenter)
self.progressBar.setTextDirection(QtGui.QProgressBar.TopToBottom)
self.progressBar.setObjectName("progressBar")
self.gridlayout.addWidget(self.progressBar,3,0,1,1)
spacerItem1 = QtGui.QSpacerItem(248,10,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Fixed)
self.gridlayout.addItem(spacerItem1,4,0,1,1)
self.hboxlayout = QtGui.QHBoxLayout()
self.hboxlayout.setObjectName("hboxlayout")
spacerItem2 = QtGui.QSpacerItem(140,27,QtGui.QSizePolicy.MinimumExpanding,QtGui.QSizePolicy.Minimum)
self.hboxlayout.addItem(spacerItem2)
self.buttonSkip = QtGui.QPushButton(QgsPluginInstallerFetchingDialog)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.buttonSkip.sizePolicy().hasHeightForWidth())
self.buttonSkip.setSizePolicy(sizePolicy)
self.buttonSkip.setMinimumSize(QtCore.QSize(180,0))
self.buttonSkip.setFocusPolicy(QtCore.Qt.NoFocus)
self.buttonSkip.setAutoDefault(False)
self.buttonSkip.setDefault(False)
self.buttonSkip.setFlat(False)
self.buttonSkip.setObjectName("buttonSkip")
self.hboxlayout.addWidget(self.buttonSkip)
spacerItem3 = QtGui.QSpacerItem(140,27,QtGui.QSizePolicy.MinimumExpanding,QtGui.QSizePolicy.Minimum)
self.hboxlayout.addItem(spacerItem3)
self.gridlayout.addLayout(self.hboxlayout,5,0,1,1)
self.treeWidget = QtGui.QTreeWidget(QgsPluginInstallerFetchingDialog)
self.treeWidget.setEnabled(True)
self.treeWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
self.treeWidget.setProperty("showDropIndicator",QtCore.QVariant(False))
self.treeWidget.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
self.treeWidget.setHorizontalScrollMode(QtGui.QAbstractItemView.ScrollPerItem)
self.treeWidget.setRootIsDecorated(False)
self.treeWidget.setItemsExpandable(False)
self.treeWidget.setObjectName("treeWidget")
self.gridlayout.addWidget(self.treeWidget,0,0,1,1)
self.retranslateUi(QgsPluginInstallerFetchingDialog)
QtCore.QObject.connect(self.buttonSkip,QtCore.SIGNAL("clicked()"),QgsPluginInstallerFetchingDialog.reject)
QtCore.QMetaObject.connectSlotsByName(QgsPluginInstallerFetchingDialog)
def retranslateUi(self, QgsPluginInstallerFetchingDialog):
QgsPluginInstallerFetchingDialog.setWindowTitle(QtGui.QApplication.translate("QgsPluginInstallerFetchingDialog", "Fetching repositories", None, QtGui.QApplication.UnicodeUTF8))
self.label1.setText(QtGui.QApplication.translate("QgsPluginInstallerFetchingDialog", "Overall progress:", None, QtGui.QApplication.UnicodeUTF8))
self.buttonSkip.setText(QtGui.QApplication.translate("QgsPluginInstallerFetchingDialog", "Abort fetching", None, QtGui.QApplication.UnicodeUTF8))
self.treeWidget.headerItem().setText(0,QtGui.QApplication.translate("QgsPluginInstallerFetchingDialog", "Repository", None, QtGui.QApplication.UnicodeUTF8))
self.treeWidget.headerItem().setText(1,QtGui.QApplication.translate("QgsPluginInstallerFetchingDialog", "State", None, QtGui.QApplication.UnicodeUTF8))
import resources_rc

View File

@ -0,0 +1,226 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'guibase.ui'
#
# Created: Sun Sep 7 21:28:01 2008
# by: PyQt4 UI code generator 4.3
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_QgsPluginInstallerDialog(object):
def setupUi(self, QgsPluginInstallerDialog):
QgsPluginInstallerDialog.setObjectName("QgsPluginInstallerDialog")
QgsPluginInstallerDialog.resize(QtCore.QSize(QtCore.QRect(0,0,769,395).size()).expandedTo(QgsPluginInstallerDialog.minimumSizeHint()))
QgsPluginInstallerDialog.setWindowIcon(QtGui.QIcon(":/plugins/installer/qgis-icon.png"))
self.gridlayout = QtGui.QGridLayout(QgsPluginInstallerDialog)
self.gridlayout.setObjectName("gridlayout")
self.tabWidget = QtGui.QTabWidget(QgsPluginInstallerDialog)
self.tabWidget.setObjectName("tabWidget")
self.tab = QtGui.QWidget()
self.tab.setObjectName("tab")
self.vboxlayout = QtGui.QVBoxLayout(self.tab)
self.vboxlayout.setObjectName("vboxlayout")
self.hboxlayout = QtGui.QHBoxLayout()
self.hboxlayout.setObjectName("hboxlayout")
self.label_5 = QtGui.QLabel(self.tab)
self.label_5.setEnabled(True)
self.label_5.setObjectName("label_5")
self.hboxlayout.addWidget(self.label_5)
self.lineFilter = QtGui.QLineEdit(self.tab)
self.lineFilter.setEnabled(True)
self.lineFilter.setObjectName("lineFilter")
self.hboxlayout.addWidget(self.lineFilter)
self.comboFilter1 = QtGui.QComboBox(self.tab)
self.comboFilter1.setEnabled(True)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.comboFilter1.sizePolicy().hasHeightForWidth())
self.comboFilter1.setSizePolicy(sizePolicy)
self.comboFilter1.setObjectName("comboFilter1")
self.hboxlayout.addWidget(self.comboFilter1)
self.comboFilter2 = QtGui.QComboBox(self.tab)
self.comboFilter2.setEnabled(True)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred,QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.comboFilter2.sizePolicy().hasHeightForWidth())
self.comboFilter2.setSizePolicy(sizePolicy)
self.comboFilter2.setObjectName("comboFilter2")
self.hboxlayout.addWidget(self.comboFilter2)
self.vboxlayout.addLayout(self.hboxlayout)
self.treePlugins = QtGui.QTreeWidget(self.tab)
self.treePlugins.setAlternatingRowColors(True)
self.treePlugins.setRootIsDecorated(False)
self.treePlugins.setItemsExpandable(False)
self.treePlugins.setSortingEnabled(True)
self.treePlugins.setAllColumnsShowFocus(True)
self.treePlugins.setObjectName("treePlugins")
self.vboxlayout.addWidget(self.treePlugins)
self.hboxlayout1 = QtGui.QHBoxLayout()
self.hboxlayout1.setObjectName("hboxlayout1")
spacerItem = QtGui.QSpacerItem(40,20,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Minimum)
self.hboxlayout1.addItem(spacerItem)
self.buttonInstall = QtGui.QPushButton(self.tab)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.buttonInstall.sizePolicy().hasHeightForWidth())
self.buttonInstall.setSizePolicy(sizePolicy)
self.buttonInstall.setMinimumSize(QtCore.QSize(160,0))
self.buttonInstall.setObjectName("buttonInstall")
self.hboxlayout1.addWidget(self.buttonInstall)
self.buttonUninstall = QtGui.QPushButton(self.tab)
self.buttonUninstall.setEnabled(True)
self.buttonUninstall.setObjectName("buttonUninstall")
self.hboxlayout1.addWidget(self.buttonUninstall)
self.vboxlayout.addLayout(self.hboxlayout1)
self.tabWidget.addTab(self.tab,"")
self.tab_2 = QtGui.QWidget()
self.tab_2.setObjectName("tab_2")
self.gridlayout1 = QtGui.QGridLayout(self.tab_2)
self.gridlayout1.setObjectName("gridlayout1")
self.treeRepositories = QtGui.QTreeWidget(self.tab_2)
self.treeRepositories.setRootIsDecorated(False)
self.treeRepositories.setItemsExpandable(False)
self.treeRepositories.setObjectName("treeRepositories")
self.gridlayout1.addWidget(self.treeRepositories,0,0,1,7)
self.checkUpdates = QtGui.QCheckBox(self.tab_2)
self.checkUpdates.setObjectName("checkUpdates")
self.gridlayout1.addWidget(self.checkUpdates,1,0,1,1)
spacerItem1 = QtGui.QSpacerItem(30,20,QtGui.QSizePolicy.Preferred,QtGui.QSizePolicy.Minimum)
self.gridlayout1.addItem(spacerItem1,1,1,1,1)
self.buttonFetchRepositories = QtGui.QPushButton(self.tab_2)
self.buttonFetchRepositories.setEnabled(True)
self.buttonFetchRepositories.setObjectName("buttonFetchRepositories")
self.gridlayout1.addWidget(self.buttonFetchRepositories,1,2,1,1)
spacerItem2 = QtGui.QSpacerItem(40,20,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Minimum)
self.gridlayout1.addItem(spacerItem2,1,3,1,1)
self.buttonAddRep = QtGui.QPushButton(self.tab_2)
self.buttonAddRep.setObjectName("buttonAddRep")
self.gridlayout1.addWidget(self.buttonAddRep,1,4,1,1)
self.buttonEditRep = QtGui.QPushButton(self.tab_2)
self.buttonEditRep.setObjectName("buttonEditRep")
self.gridlayout1.addWidget(self.buttonEditRep,1,5,1,1)
self.buttonDeleteRep = QtGui.QPushButton(self.tab_2)
self.buttonDeleteRep.setObjectName("buttonDeleteRep")
self.gridlayout1.addWidget(self.buttonDeleteRep,1,6,1,1)
self.tabWidget.addTab(self.tab_2,"")
self.gridlayout.addWidget(self.tabWidget,0,0,1,1)
self.hboxlayout2 = QtGui.QHBoxLayout()
self.hboxlayout2.setObjectName("hboxlayout2")
self.label_3 = QtGui.QLabel(QgsPluginInstallerDialog)
self.label_3.setObjectName("label_3")
self.hboxlayout2.addWidget(self.label_3)
self.buttonClose = QtGui.QPushButton(QgsPluginInstallerDialog)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.buttonClose.sizePolicy().hasHeightForWidth())
self.buttonClose.setSizePolicy(sizePolicy)
self.buttonClose.setObjectName("buttonClose")
self.hboxlayout2.addWidget(self.buttonClose)
self.gridlayout.addLayout(self.hboxlayout2,1,0,1,1)
self.retranslateUi(QgsPluginInstallerDialog)
self.tabWidget.setCurrentIndex(0)
QtCore.QObject.connect(self.buttonClose,QtCore.SIGNAL("released()"),QgsPluginInstallerDialog.close)
QtCore.QMetaObject.connectSlotsByName(QgsPluginInstallerDialog)
QgsPluginInstallerDialog.setTabOrder(self.tabWidget,self.lineFilter)
QgsPluginInstallerDialog.setTabOrder(self.lineFilter,self.comboFilter1)
QgsPluginInstallerDialog.setTabOrder(self.comboFilter1,self.comboFilter2)
QgsPluginInstallerDialog.setTabOrder(self.comboFilter2,self.treePlugins)
QgsPluginInstallerDialog.setTabOrder(self.treePlugins,self.buttonInstall)
QgsPluginInstallerDialog.setTabOrder(self.buttonInstall,self.buttonUninstall)
QgsPluginInstallerDialog.setTabOrder(self.buttonUninstall,self.buttonClose)
QgsPluginInstallerDialog.setTabOrder(self.buttonClose,self.treeRepositories)
QgsPluginInstallerDialog.setTabOrder(self.treeRepositories,self.buttonFetchRepositories)
QgsPluginInstallerDialog.setTabOrder(self.buttonFetchRepositories,self.checkUpdates)
QgsPluginInstallerDialog.setTabOrder(self.checkUpdates,self.buttonAddRep)
QgsPluginInstallerDialog.setTabOrder(self.buttonAddRep,self.buttonEditRep)
QgsPluginInstallerDialog.setTabOrder(self.buttonEditRep,self.buttonDeleteRep)
def retranslateUi(self, QgsPluginInstallerDialog):
QgsPluginInstallerDialog.setWindowTitle(QtGui.QApplication.translate("QgsPluginInstallerDialog", "QGIS Python Plugin Installer", None, QtGui.QApplication.UnicodeUTF8))
QgsPluginInstallerDialog.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerDialog", "QGIS Plugin Installer", None, QtGui.QApplication.UnicodeUTF8))
self.label_5.setText(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Filter:", None, QtGui.QApplication.UnicodeUTF8))
self.lineFilter.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Display only plugins containing this word in their metadata", None, QtGui.QApplication.UnicodeUTF8))
self.lineFilter.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Display only plugins containing this word in their metadata", None, QtGui.QApplication.UnicodeUTF8))
self.comboFilter1.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Display only plugins from given repository", None, QtGui.QApplication.UnicodeUTF8))
self.comboFilter1.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Display only plugins from given repository", None, QtGui.QApplication.UnicodeUTF8))
self.comboFilter1.addItem(QtGui.QApplication.translate("QgsPluginInstallerDialog", "all repositories", None, QtGui.QApplication.UnicodeUTF8))
self.comboFilter2.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Display only plugins with matching status", None, QtGui.QApplication.UnicodeUTF8))
self.comboFilter2.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Display only plugins with matching status", None, QtGui.QApplication.UnicodeUTF8))
self.treePlugins.headerItem().setText(0,QtGui.QApplication.translate("QgsPluginInstallerDialog", "Status", None, QtGui.QApplication.UnicodeUTF8))
self.treePlugins.headerItem().setText(1,QtGui.QApplication.translate("QgsPluginInstallerDialog", "Name", None, QtGui.QApplication.UnicodeUTF8))
self.treePlugins.headerItem().setText(2,QtGui.QApplication.translate("QgsPluginInstallerDialog", "Version", None, QtGui.QApplication.UnicodeUTF8))
self.treePlugins.headerItem().setText(3,QtGui.QApplication.translate("QgsPluginInstallerDialog", "Description", None, QtGui.QApplication.UnicodeUTF8))
self.treePlugins.headerItem().setText(4,QtGui.QApplication.translate("QgsPluginInstallerDialog", "Author", None, QtGui.QApplication.UnicodeUTF8))
self.treePlugins.headerItem().setText(5,QtGui.QApplication.translate("QgsPluginInstallerDialog", "Repository", None, QtGui.QApplication.UnicodeUTF8))
self.buttonInstall.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Install, reinstall or upgrade the selected plugin", None, QtGui.QApplication.UnicodeUTF8))
self.buttonInstall.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Install, reinstall or upgrade the selected plugin", None, QtGui.QApplication.UnicodeUTF8))
self.buttonInstall.setText(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Install/upgrade plugin", None, QtGui.QApplication.UnicodeUTF8))
self.buttonUninstall.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Uninstall the selected plugin", None, QtGui.QApplication.UnicodeUTF8))
self.buttonUninstall.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Uninstall the selected plugin", None, QtGui.QApplication.UnicodeUTF8))
self.buttonUninstall.setText(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Uninstall plugin", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), QtGui.QApplication.translate("QgsPluginInstallerDialog", "Plugins", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabToolTip(self.tabWidget.indexOf(self.tab),QtGui.QApplication.translate("QgsPluginInstallerDialog", "List of available and installed plugins", None, QtGui.QApplication.UnicodeUTF8))
self.treeRepositories.headerItem().setText(0,QtGui.QApplication.translate("QgsPluginInstallerDialog", "Status", None, QtGui.QApplication.UnicodeUTF8))
self.treeRepositories.headerItem().setText(1,QtGui.QApplication.translate("QgsPluginInstallerDialog", "Name", None, QtGui.QApplication.UnicodeUTF8))
self.treeRepositories.headerItem().setText(2,QtGui.QApplication.translate("QgsPluginInstallerDialog", "URL", None, QtGui.QApplication.UnicodeUTF8))
self.checkUpdates.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Allow the Installer to look for updates and news in enabled repositories on QGIS startup", None, QtGui.QApplication.UnicodeUTF8))
self.checkUpdates.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Allow the Installer to look for updates and news in enabled repositories on QGIS startup", None, QtGui.QApplication.UnicodeUTF8))
self.checkUpdates.setText(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Check for updates on startup", None, QtGui.QApplication.UnicodeUTF8))
self.buttonFetchRepositories.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Add third party plugin repositories to the list", None, QtGui.QApplication.UnicodeUTF8))
self.buttonFetchRepositories.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Add third party plugin repositories to the list", None, QtGui.QApplication.UnicodeUTF8))
self.buttonFetchRepositories.setText(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Add 3rd party repositories", None, QtGui.QApplication.UnicodeUTF8))
self.buttonAddRep.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Add a new plugin repository", None, QtGui.QApplication.UnicodeUTF8))
self.buttonAddRep.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Add a new plugin repository", None, QtGui.QApplication.UnicodeUTF8))
self.buttonAddRep.setText(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Add...", None, QtGui.QApplication.UnicodeUTF8))
self.buttonEditRep.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Edit the selected repository", None, QtGui.QApplication.UnicodeUTF8))
self.buttonEditRep.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Edit the selected repository", None, QtGui.QApplication.UnicodeUTF8))
self.buttonEditRep.setText(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Edit...", None, QtGui.QApplication.UnicodeUTF8))
self.buttonDeleteRep.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Remove the selected repository", None, QtGui.QApplication.UnicodeUTF8))
self.buttonDeleteRep.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Remove the selected repository", None, QtGui.QApplication.UnicodeUTF8))
self.buttonDeleteRep.setText(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Delete", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), QtGui.QApplication.translate("QgsPluginInstallerDialog", "Repositories", None, QtGui.QApplication.UnicodeUTF8))
self.tabWidget.setTabToolTip(self.tabWidget.indexOf(self.tab_2),QtGui.QApplication.translate("QgsPluginInstallerDialog", "List of plugin repositories", None, QtGui.QApplication.UnicodeUTF8))
self.label_3.setText(QtGui.QApplication.translate("QgsPluginInstallerDialog", "The plugins will be installed to ~/.qgis/python/plugins", None, QtGui.QApplication.UnicodeUTF8))
self.buttonClose.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Close the Installer window", None, QtGui.QApplication.UnicodeUTF8))
self.buttonClose.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Close the Installer window", None, QtGui.QApplication.UnicodeUTF8))
self.buttonClose.setText(QtGui.QApplication.translate("QgsPluginInstallerDialog", "Close", None, QtGui.QApplication.UnicodeUTF8))
import resources_rc

View File

@ -0,0 +1,433 @@
<ui version="4.0" >
<author>Matthew Perry, Borys Jurgiel</author>
<class>QgsPluginInstallerDialog</class>
<widget class="QDialog" name="QgsPluginInstallerDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>769</width>
<height>395</height>
</rect>
</property>
<property name="windowTitle" >
<string>QGIS Python Plugin Installer</string>
</property>
<property name="windowIcon" >
<iconset resource="resources.qrc" >:/plugins/installer/qgis-icon.png</iconset>
</property>
<property name="whatsThis" >
<string>QGIS Plugin Installer</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QTabWidget" name="tabWidget" >
<property name="toolTip" >
<string/>
</property>
<property name="whatsThis" >
<string/>
</property>
<property name="currentIndex" >
<number>0</number>
</property>
<widget class="QWidget" name="tab" >
<attribute name="title" >
<string>Plugins</string>
</attribute>
<attribute name="toolTip" >
<string>List of available and installed plugins</string>
</attribute>
<layout class="QVBoxLayout" >
<item>
<layout class="QHBoxLayout" >
<item>
<widget class="QLabel" name="label_5" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="text" >
<string>Filter:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineFilter" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="toolTip" >
<string>Display only plugins containing this word in their metadata</string>
</property>
<property name="whatsThis" >
<string>Display only plugins containing this word in their metadata</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboFilter1" >
<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="toolTip" >
<string>Display only plugins from given repository</string>
</property>
<property name="statusTip" >
<string/>
</property>
<property name="whatsThis" >
<string>Display only plugins from given repository</string>
</property>
<item>
<property name="text" >
<string>all repositories</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboFilter2" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip" >
<string>Display only plugins with matching status</string>
</property>
<property name="whatsThis" >
<string>Display only plugins with matching status</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTreeWidget" name="treePlugins" >
<property name="alternatingRowColors" >
<bool>true</bool>
</property>
<property name="rootIsDecorated" >
<bool>false</bool>
</property>
<property name="itemsExpandable" >
<bool>false</bool>
</property>
<property name="sortingEnabled" >
<bool>true</bool>
</property>
<property name="allColumnsShowFocus" >
<bool>true</bool>
</property>
<column>
<property name="text" >
<string>Status</string>
</property>
</column>
<column>
<property name="text" >
<string>Name</string>
</property>
</column>
<column>
<property name="text" >
<string>Version</string>
</property>
</column>
<column>
<property name="text" >
<string>Description</string>
</property>
</column>
<column>
<property name="text" >
<string>Author</string>
</property>
</column>
<column>
<property name="text" >
<string>Repository</string>
</property>
</column>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="buttonInstall" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="toolTip" >
<string>Install, reinstall or upgrade the selected plugin</string>
</property>
<property name="whatsThis" >
<string>Install, reinstall or upgrade the selected plugin</string>
</property>
<property name="text" >
<string>Install/upgrade plugin</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonUninstall" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="toolTip" >
<string>Uninstall the selected plugin</string>
</property>
<property name="whatsThis" >
<string>Uninstall the selected plugin</string>
</property>
<property name="text" >
<string>Uninstall plugin</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2" >
<attribute name="title" >
<string>Repositories</string>
</attribute>
<attribute name="toolTip" >
<string>List of plugin repositories</string>
</attribute>
<layout class="QGridLayout" >
<item row="0" column="0" colspan="7" >
<widget class="QTreeWidget" name="treeRepositories" >
<property name="rootIsDecorated" >
<bool>false</bool>
</property>
<property name="itemsExpandable" >
<bool>false</bool>
</property>
<column>
<property name="text" >
<string>Status</string>
</property>
</column>
<column>
<property name="text" >
<string>Name</string>
</property>
</column>
<column>
<property name="text" >
<string>URL</string>
</property>
</column>
</widget>
</item>
<item row="1" column="0" >
<widget class="QCheckBox" name="checkUpdates" >
<property name="toolTip" >
<string>Allow the Installer to look for updates and news in enabled repositories on QGIS startup</string>
</property>
<property name="statusTip" >
<string/>
</property>
<property name="whatsThis" >
<string>Allow the Installer to look for updates and news in enabled repositories on QGIS startup</string>
</property>
<property name="text" >
<string>Check for updates on startup</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" >
<size>
<width>30</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2" >
<widget class="QPushButton" name="buttonFetchRepositories" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="toolTip" >
<string>Add third party plugin repositories to the list</string>
</property>
<property name="whatsThis" >
<string>Add third party plugin repositories to the list</string>
</property>
<property name="text" >
<string>Add 3rd party repositories</string>
</property>
</widget>
</item>
<item row="1" column="3" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="4" >
<widget class="QPushButton" name="buttonAddRep" >
<property name="toolTip" >
<string>Add a new plugin repository</string>
</property>
<property name="whatsThis" >
<string>Add a new plugin repository</string>
</property>
<property name="text" >
<string>Add...</string>
</property>
</widget>
</item>
<item row="1" column="5" >
<widget class="QPushButton" name="buttonEditRep" >
<property name="toolTip" >
<string>Edit the selected repository</string>
</property>
<property name="whatsThis" >
<string>Edit the selected repository</string>
</property>
<property name="text" >
<string>Edit...</string>
</property>
</widget>
</item>
<item row="1" column="6" >
<widget class="QPushButton" name="buttonDeleteRep" >
<property name="toolTip" >
<string>Remove the selected repository</string>
</property>
<property name="whatsThis" >
<string>Remove the selected repository</string>
</property>
<property name="text" >
<string>Delete</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item row="1" column="0" >
<layout class="QHBoxLayout" >
<item>
<widget class="QLabel" name="label_3" >
<property name="whatsThis" >
<string/>
</property>
<property name="text" >
<string>The plugins will be installed to ~/.qgis/python/plugins</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonClose" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip" >
<string>Close the Installer window</string>
</property>
<property name="whatsThis" >
<string>Close the Installer window</string>
</property>
<property name="text" >
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>lineFilter</tabstop>
<tabstop>comboFilter1</tabstop>
<tabstop>comboFilter2</tabstop>
<tabstop>treePlugins</tabstop>
<tabstop>buttonInstall</tabstop>
<tabstop>buttonUninstall</tabstop>
<tabstop>buttonClose</tabstop>
<tabstop>treeRepositories</tabstop>
<tabstop>buttonFetchRepositories</tabstop>
<tabstop>checkUpdates</tabstop>
<tabstop>buttonAddRep</tabstop>
<tabstop>buttonEditRep</tabstop>
<tabstop>buttonDeleteRep</tabstop>
</tabstops>
<resources>
<include location="resources.qrc" />
</resources>
<connections>
<connection>
<sender>buttonClose</sender>
<signal>released()</signal>
<receiver>QgsPluginInstallerDialog</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel" >
<x>710</x>
<y>447</y>
</hint>
<hint type="destinationlabel" >
<x>380</x>
<y>235</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,584 @@
# -*- coding: utf-8 -*-
"""
qgis_plugins.py
Copyright (C) 2007-2008 Matthew Perry
Copyright (C) 2008 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. *
* *
***************************************************************************/
"""
from PyQt4.QtCore import *
from PyQt4.QtXml import QDomDocument
from PyQt4.QtNetwork import QHttp, QNetworkProxy
from qgis.core import *
from unzip import unzip
"""
Data structure:
mRepositories = dict of dicts: {repoName : {"url" string,
"enabled" bool,
"valid" bool,
"QHttp" QHttp,
"Relay" Relay, # Relay object for transmitting signals from QHttp with adding the repoName information
"xmlData" QDomDocument,
"state" int, (0 - disabled, 1-loading, 2-loaded ok, 3-error (to be retried), 4-rejected)
"error" QString}}
mPlugins = dict of dicts {id : {"name" string,
"version_avail" string,
"version_inst" string,
"desc_repo" string,
"desc_local" string,
"author" string,
"status" string, ("not installed", "installed", "upgradeable", "orphan", "new", "newer", "invalid")
"homepage" string,
"url" string,
"filename" string,
"repository" string,
"localdir" string,
"read-only" boolean}}
"""
reposGroup = "/Qgis/plugin-repos"
settingsGroup = "/Qgis/plugin-installer"
seenPluginGroup = "/Qgis/plugin-seen"
# knownRepos: (name, url for QGIS 0.x, url for QGIS 1.x, possible depreciated url, another possible depreciated url)
knownRepos = [("Official QGIS Repository","http://spatialserver.net/cgi-bin/pyqgis_plugin.rb","http://spatialserver.net/cgi-bin/pyqgis_plugin.rb","",""),
("Carson Farmer's Repository","http://www.ftools.ca/cfarmerQgisRepo.xml","","http://www.geog.uvic.ca/spar/carson/cfarmerQgisRepo.xml",""),
("Barry Rowlingson's Repository","http://www.maths.lancs.ac.uk/~rowlings/Qgis/Plugins/plugins.xml","","",""),
("Borys Jurgiel's Repository","http://bwj.aster.net.pl/qgis-oldapi/plugins.xml","http://bwj.aster.net.pl/qgis/plugins.xml","",""),
("Faunalia Repository","http://faunalia.it/qgis/plugins.xml","","","")]
# --- class Relay ----------------------------------------------------------------------- #
class Relay(QObject):
""" Relay object for transmitting signals from QHttp with adding the repoName information """
# ----------------------------------------- #
def __init__(self, key):
QObject.__init__(self)
self.key = key
def stateChanged(self, state):
self.emit(SIGNAL("anythingChanged(QString, int, int)"), self.key, state, 0)
# ----------------------------------------- #
def dataReadProgress(self, done, total):
state = 4
if total:
progress = int(float(done)/float(total)*100)
else:
progress = 0
self.emit(SIGNAL("anythingChanged(QString, int, int)"), self.key, state, progress)
# --- /class Relay ---------------------------------------------------------------------- #
# --- class Repositories ----------------------------------------------------------------- #
class Repositories(QObject):
# ----------------------------------------- #
def __init__(self):
QObject.__init__(self)
self.mRepositories = {}
self.httpId = {} # {httpId : repoName}
self.QGISver = int(str(QGis.qgisVersion)[0])
# ----------------------------------------- #
def addKnownRepos(self):
presentURLs = []
for i in self.all().values():
presentURLs += [str(i["url"])]
for i in knownRepos:
if i[self.QGISver+1] and presentURLs.count(i[self.QGISver+1]) == 0:
settings = QSettings()
settings.beginGroup(reposGroup)
repoName = QString(i[0])
if self.all().has_key(repoName):
repoName = repoName + "(2)"
# add to settings
settings.setValue(repoName+"/url", QVariant(i[self.QGISver+1]))
settings.setValue(repoName+"/enabled", QVariant(True))
# ----------------------------------------- #
def all(self):
return self.mRepositories
# ----------------------------------------- #
def allEnabled(self):
repos = {}
for i in self.mRepositories:
if self.mRepositories[i]["enabled"] and self.mRepositories[i]["valid"]:
repos[i] = self.mRepositories[i]
return repos
# ----------------------------------------- #
def allUnavailable(self):
repos = {}
for i in self.mRepositories:
if self.mRepositories[i]["enabled"] and self.mRepositories[i]["valid"] and self.mRepositories[i]["state"] == 3:
repos[i] = self.mRepositories[i]
return repos
# ----------------------------------------- #
def setRepositoryData(self,reposName, key, value):
self.mRepositories[reposName][key] = value
# ----------------------------------------- #
def rename(self,oldName, newName):
if oldName == newName:
return
self.mRepositories[newName] = self.mRepositories[oldName]
del self.mRepositories[oldName]
# ----------------------------------------- #
def checkingOnStart(self):
settings = QSettings()
return settings.value(settingsGroup+"/checkOnStart", QVariant(True)).toBool()
# ----------------------------------------- #
def setCheckingOnStart(self, state):
settings = QSettings()
settings.setValue(settingsGroup+"/checkOnStart", QVariant(state))
# ----------------------------------------- #
def load(self):
""" populate the mRepositories dict"""
self.mRepositories = {}
settings = QSettings()
settings.beginGroup(reposGroup)
# first, update the QSettings repositories if needed
if len(settings.childGroups()) == 0: # add the default repository when there isn't any
settings.setValue(self.knownRepos[0][0]+"/url", QVariant(self.knownRepos[0][self.QGISver+1]))
else: # else update invalid urls
for key in settings.childGroups():
url = settings.value(key+"/url", QVariant()).toString()
allOk = True
for repo in knownRepos:
if repo[3] == url or repo[4] == url or (repo[self.QGISver+1] != url and repo[int(not self.QGISver)+1] == url):
if repo[self.QGISver+1]: #update the URL
settings.setValue(key+"/url", QVariant(repo[self.QGISver+1]))
settings.setValue(key+"/valid", QVariant(True))
allOk = False
else: # mark as invalid
settings.setValue(key+"/valid", QVariant(False))
allOk = False
if allOk: # marking as valid if no problem.
settings.setValue(key+"/valid", QVariant(True))
for key in settings.childGroups():
self.mRepositories[key] = {}
self.mRepositories[key]["url"] = settings.value(key+"/url", QVariant()).toString()
self.mRepositories[key]["enabled"] = settings.value(key+"/enabled", QVariant(True)).toBool()
self.mRepositories[key]["valid"] = settings.value(key+"/valid", QVariant(True)).toBool()
self.mRepositories[key]["QHttp"] = QHttp()
self.mRepositories[key]["Relay"] = Relay(key)
self.mRepositories[key]["xmlData"] = QBuffer()
self.mRepositories[key]["state"] = 0
self.mRepositories[key]["error"] = QString()
settings.endGroup()
# ----------------------------------------- #
def requestFetching(self,key):
self.mRepositories[key]["state"] = 1
url = QUrl(self.mRepositories[key]["url"])
path = QString(url.toPercentEncoding(url.path(), "!$&'()*+,;=:@/"))
self.mRepositories[key]["QHttp"] = QHttp(url.host())
self.connect(self.mRepositories[key]["QHttp"], SIGNAL("requestFinished (int, bool)"), self.xmlDownloaded)
self.connect(self.mRepositories[key]["QHttp"], SIGNAL("stateChanged ( int )"), self.mRepositories[key]["Relay"].stateChanged)
self.connect(self.mRepositories[key]["QHttp"], SIGNAL("dataReadProgress ( int , int )"), self.mRepositories[key]["Relay"].dataReadProgress)
self.connect(self.mRepositories[key]["Relay"], SIGNAL("anythingChanged(QString, int, int)"), self, SIGNAL("anythingChanged (QString, int, int)"))
i = self.mRepositories[key]["QHttp"].get(path, self.mRepositories[key]["xmlData"])
self.httpId[i] = key
# ----------------------------------------- #
def fetchingInProgress(self):
for key in self.mRepositories:
if self.mRepositories[key]["state"] == 1:
return True
return False
# ----------------------------------------- #
def killConnection(self, key):
if self.mRepositories[key]["QHttp"].state():
self.mRepositories[key]["QHttp"].abort()
# ----------------------------------------- #
def xmlDownloaded(self,nr,state):
#print reposName, nr, state
if not self.httpId.has_key(nr):
return
reposName = self.httpId[nr]
if state: # fetching failed
self.mRepositories[reposName]["state"] = 3
self.mRepositories[reposName]["error"] = self.mRepositories[reposName]["QHttp"].errorString()
#print "Repository fetching failed! " , reposName , str(self.mRepositories[reposName]["error"])
else:
repoData = self.mRepositories[reposName]["xmlData"]
reposXML = QDomDocument()
reposXML.setContent(repoData.data())
pluginNodes = reposXML.elementsByTagName("pyqgis_plugin")
if pluginNodes.size():
for i in range(pluginNodes.size()):
name = QFileInfo(pluginNodes.item(i).firstChildElement("download_url").text().trimmed()).fileName()
name = str(name[0:len(name)-4])
plugin = {}
plugin[name] = {
"name" : pluginNodes.item(i).toElement().attribute("name"),
"version_avail" : pluginNodes.item(i).toElement().attribute("version"),
"desc_repo" : pluginNodes.item(i).firstChildElement("description").text().trimmed(),
"desc_local" : "",
"author" : pluginNodes.item(i).firstChildElement("author_name").text().trimmed(),
"homepage" : pluginNodes.item(i).firstChildElement("homepage").text().trimmed(),
"url" : pluginNodes.item(i).firstChildElement("download_url").text().trimmed(),
"filename" : pluginNodes.item(i).firstChildElement("file_name").text().trimmed(),
"status" : "not installed",
"version_inst" : "",
"repository" : reposName,
"localdir" : name,
"read-only" : False}
plugins.addPlugin(plugin)
plugins.workarounds()
self.mRepositories[reposName]["state"] = 2
else:
#print "Repository parsing error"
self.mRepositories[reposName]["state"] = 3
self.mRepositories[reposName]["error"] = QCoreApplication.translate("QgsPluginInstaller","Couldn't parse output from the repository")
self.emit(SIGNAL("repositoryFetched(QString)"), reposName )
# is the checking done?
if not self.fetchingInProgress():
plugins.getAllInstalled()
self.emit(SIGNAL("checkingDone()"))
# --- /class Repositories ---------------------------------------------------------------- #
# --- class Plugins ---------------------------------------------------------------------- #
class Plugins(QObject):
# ----------------------------------------- #
def __init__(self):
QObject.__init__(self)
self.mPlugins = {}
# ----------------------------------------- #
def all(self):
return self.mPlugins
# ----------------------------------------- #
def firstByName(self, name):
plugins = [i for i in self.mPlugins if self.mPlugins[i]["name"] == name]
if plugins:
return plugins[0]
return None
# ----------------------------------------- #
def setPluginData(self, pluginName, key, value):
self.mPlugins[pluginName][key] = value
# ----------------------------------------- #
def clear(self):
""" clear the plugins dict"""
self.mPlugins = {}
# ----------------------------------------- #
def normalizeVersion(self,ver):
if not ver:
return QString()
if ver.toUpper().left(7) == "VERSION":
ver.remove(0,7)
elif ver.toUpper().left(4) == "VER.":
ver.remove(0,4)
if ver[0] == " ":
ver.remove(0,1)
return ver
# ----------------------------------------- #
def compareVersions(self,a,b):
# -------- #
def classify(s):
if s in [".","-","_"," "]:
return 0
try:
float(s)
return 1
except:
return 2
# -------- #
def chop(s):
s2 = [s[0]]
for i in range(1,len(s)):
if classify(s[i]) == 0:
pass
elif classify(s[i]) == classify(s[i-1]):
s2[len(s2)-1] += s[i]
else:
s2 += [s[i]]
return s2
# -------- #
def compare(s1,s2):
# check if the matter is easy solvable:
if s1 == s2:
return 0
# try to compare as numeric values:
try:
if s1[0] == '0' or s2[0] == '0':
s1 = '0.' + s1
s2 = '0.' + s2
if float(s1) == float(s2):
return 0
elif float(s1) > float(s2):
return 1
else:
return 2
except:
pass
# set ALPHA < BETA < RC < FINAL < ANYTHING_ELSE
if s1 == 'FINAL':
s1 = 'Z' + s1
elif not s1 in ['ALPHA','BETA','RC']:
s1 = 'ZZ' + s1
if s2 == 'FINAL':
s2 = 'Z' + s2
elif not s2 in ['ALPHA','BETA','RC']:
s2 = 'ZZ' + s2
# the real test:
if s1 > s2:
return 1
else:
return 2
# -------- #
if not a or not b:
return 0
a = unicode(a).upper()
b = unicode(b).upper()
if a == b:
return 0
v1 = chop(a)
v2 = chop(b)
l = len(v1)
if l > len(v2):
l = len(v2)
for i in range(l):
if compare(v1[i],v2[i]):
return compare(v1[i],v2[i])
if len(v1) > l:
return compare(v1[l],u'')
if len(v2) > l:
return compare(u'',v2[l])
# if everything else fails...
if unicode(a) > unicode(b):
return 1
else:
return 2
# ----------------------------------------- #
def addPlugin(self, plugins):
key = plugins.keys()[0]
plugin = plugins[key]
plugin["version_avail"] = self.normalizeVersion(QString(plugin["version_avail"]))
plugin["version_inst"] = self.normalizeVersion(QString(plugin["version_inst"]))
if not self.mPlugins.has_key(key) or self.compareVersions(self.mPlugins[key]["version_avail"],plugin["version_avail"]) == 2:
self.mPlugins[key] = plugin # add the plugin if not present yet or if is newer than existing one
# ----------------------------------------- #
def updatePlugin(self, key, readOnly):
try:
exec("import "+ key)
try:
exec("nam = %s.name()" % key)
except:
nam = ""
try:
exec("ver = %s.version()" % key)
except:
ver = ""
try:
exec("desc = %s.description()" % key)
except:
desc = ""
try:
exec("auth = %s.author_name()" % key)
except:
auth = ""
try:
exec("homepage = %s.homepage()" % key)
except:
homepage = ""
stat = ""
except:
nam = key
stat = "invalid"
ver = ""
desc = ""
auth = ""
homepage = ""
normVer = self.normalizeVersion(QString(ver))
plugin = {
"name" : nam,
"version_inst" : normVer,
"version_avail" : "",
"desc_local" : desc,
"desc_repo" : "",
"author" : auth,
"homepage" : homepage,
"url" : "",
"filename" : "",
"status" : stat,
"repository" : "",
"localdir" : key,
"read-only" : readOnly}
if not self.mPlugins.has_key(key):
self.mPlugins[key] = plugin # just add a new plugin
else:
self.mPlugins[key]["localdir"] = plugin["localdir"]
self.mPlugins[key]["read-only"] = plugin["read-only"]
if plugin["status"] == "invalid":
self.mPlugins[key]["status"] = plugin["status"]
else:
self.mPlugins[key]["name"] = plugin["name"] # local name has higher priority, except invalid plugins
self.mPlugins[key]["version_inst"] = plugin["version_inst"]
self.mPlugins[key]["desc_local"] = plugin["desc_local"]
if plugin["author"]:
self.mPlugins[key]["author"] = plugin["author"] #local author name has higher priority, if exists
if plugin["homepage"]:
self.mPlugins[key]["homepage"] = plugin["homepage"] # local homepage adress has higher priority, if exists
# set status
#
# installed available status
# ---------------------------------------
# none any "not installed" (will be later checked if is "new")
# any none "orphan"
# same same "installed"
# less greater "upgradeable"
# greater less "newer"
# *marked as invalid* "invalid"
if self.mPlugins[key]["status"] == "invalid":
pass
elif not self.mPlugins[key]["version_inst"]:
self.mPlugins[key]["status"] = "not installed"
elif not self.mPlugins[key]["version_avail"]:
self.mPlugins[key]["status"] = "orphan"
elif self.compareVersions(self.mPlugins[key]["version_avail"],self.mPlugins[key]["version_inst"]) == 0:
self.mPlugins[key]["status"] = "installed"
elif self.compareVersions(self.mPlugins[key]["version_avail"],self.mPlugins[key]["version_inst"]) == 1:
self.mPlugins[key]["status"] = "upgradeable"
else:
self.mPlugins[key]["status"] = "newer"
# ----------------------------------------- #
def getAllInstalled(self):
""" update the mPlugins dict with alredy installed plugins """
#print "getting list of installed plugins"
# first, try to add the read-only plugins...
try:
pluginDir = QDir.cleanPath(unicode(QgsApplication.pkgDataPath(),'utf-8') + "/python/plugins")
pluginDir = QDir(pluginDir)
pluginDir.setFilter(QDir.AllDirs)
except:
return QCoreApplication.translate("QgsPluginInstaller","Couldn't open the system plugin directory")
for key in pluginDir.entryList():
key = str(key)
if not key in [".",".."]:
self.updatePlugin(key, True)
# ...then try to add locally installed ones
try:
pluginDir = QDir.cleanPath(unicode(QgsApplication.qgisSettingsDirPath(),'utf-8') + "/python/plugins")
pluginDir = QDir(pluginDir)
pluginDir.setFilter(QDir.AllDirs)
except:
return QCoreApplication.translate("QgsPluginInstaller","Couldn't open the local plugin directory")
for key in pluginDir.entryList():
key = str(key)
if not key in [".",".."]:
self.updatePlugin(key, False)
# ----------------------------------------- #
def markNews(self):
""" mark all new plugins as new """
#print "marking the new plugins"
settings = QSettings()
seenPlugins = settings.value(seenPluginGroup, QVariant(QStringList(self.mPlugins.keys()))).toStringList()
if len(seenPlugins) > 0:
for i in self.mPlugins.keys():
if seenPlugins.count(QString(i)) == 0 and self.mPlugins[i]["status"] == "not installed":
self.mPlugins[i]["status"] = "new"
# ----------------------------------------- #
def updateSeenPluginsList(self):
""" update the list of all seen plugins """
#print "updating the list of seen plugins"
settings = QSettings()
seenPlugins = settings.value(seenPluginGroup, QVariant(QStringList(self.mPlugins.keys()))).toStringList()
for i in self.mPlugins.keys():
if seenPlugins.count(QString(i)) == 0:
seenPlugins += [i]
settings.setValue(seenPluginGroup, QVariant(QStringList(seenPlugins)))
# ----------------------------------------- #
def isThereAnythingNew(self):
for i in self.mPlugins.values():
if i["status"] in ["upgradeable","new"]:
return True
return False
# ----------------------------------------- #
def workarounds(self):
if self.mPlugins.has_key("postgps") and self.mPlugins["postgps"]["version_avail"] == "0.2":
self.mPlugins["postgps"]["version_avail"] = "0.01"
if self.mPlugins.has_key("select") and self.mPlugins["select"]["version_avail"] == "0.1":
self.mPlugins["select"]["version_avail"] = "0.2"
# --- /class Plugins --------------------------------------------------------------------- #
# public members:
repositories = Repositories()
plugins = Plugins()

View File

@ -0,0 +1,709 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2008 Matthew Perry
Copyright (C) 2008 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. *
* *
***************************************************************************/
"""
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import QgsApplication, QgsContextHelp
import sys
from fetchingbase import Ui_QgsPluginInstallerFetchingDialog
from installingbase import Ui_QgsPluginInstallerInstallingDialog
from repositorybase import Ui_QgsPluginInstallerRepositoryDetailsDialog
from pluginerrorbase import Ui_QgsPluginInstallerPluginErrorDialog
from guibase import Ui_QgsPluginInstallerDialog
from installer_data import *
# --- common functions ------------------------------------------------------------------- #
def removeDir(path):
result = QString()
if not QFile(path).exists():
result = QCoreApplication.translate("QgsPluginInstaller","Plugin directory doesn't exist: ") + path
elif QFile(path).remove(): # if it's only link, just remove it without resolving.
#print " Link removing successfull: %s" % path
pass
else:
fltr = QDir.Dirs | QDir.Files | QDir.Hidden
iterator = QDirIterator(path, fltr, QDirIterator.Subdirectories)
while iterator.hasNext():
item = iterator.next()
if QFile(item).remove():
#print " File removing successfull: %s" % item
pass
fltr = QDir.Dirs | QDir.Hidden
iterator = QDirIterator(path, fltr, QDirIterator.Subdirectories)
while iterator.hasNext():
item = iterator.next()
if QDir(item).rmpath("."):
#print " Directory removing successfull: %s" % item
pass
if QFile(path).exists():
result = QCoreApplication.translate("QgsPluginInstaller","Failed to remove directory")+" "+path+" \n"+QCoreApplication.translate("QgsPluginInstaller","Check permissions or remove it manually")
return result
# --- /common functions ------------------------------------------------------------------ #
# --- class QgsPluginInstallerFetchingDialog --------------------------------------------------------------- #
class QgsPluginInstallerFetchingDialog(QDialog, Ui_QgsPluginInstallerFetchingDialog):
# ----------------------------------------- #
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("Done"),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_QgsPluginInstallerRepositoryDetailsDialog):
# ----------------------------------------- #
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_QgsPluginInstallerInstallingDialog):
# ----------------------------------------- #
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["url"])
path = QString(url.toPercentEncoding(url.path(), "!$&'()*+,;=:@/"))
fileName = plugin["filename"]
#print "Retrieving from %s" % path
tmpDir = QDir.tempPath()
tmpPath = QDir.cleanPath(tmpDir+"/"+fileName)
self.file = QFile(tmpPath)
self.http = QHttp(url.host())
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 = unicode(QFileInfo(QgsApplication.qgisUserDbFilePath()).path()+"/python/plugins")
tmpPath = unicode(self.file.fileName())
# make sure that the parent directory exists
if not QDir(pluginDir).exists():
QDir(pluginDir).mkpath(".")
#print "Extracting to plugin directory (%s)" % pluginDir
#try:
un = unzip()
un.extract(tmpPath, pluginDir) # test extract. If fails, then exception will be raised and no removing occurs
#print "Removing old plugin files if exist"
removeDir(QDir.cleanPath(pluginDir+"/"+self.plugin["localdir"])) # remove old plugin if exists
un.extract(tmpPath, pluginDir) # final extract.
#except:
#self.mResult = self.tr("Failed to unzip file to ") + pluginDir + "\n" + self.tr("check permissions")
#self.reject()
#return
try:
#print "Cleaning: removing the zip file (%s)" % tmpPath
QFile(tmpPath).remove()
except:
pass
self.close()
# ----------------------------------------- #
def abort(self):
self.http.abort()
self.mResult = self.tr("Aborted by user")
self.reject()
# --- /class QgsPluginInstallerPluginErrorDialog ------------------------------------------------------------- #
# --- class QgsPluginInstallerPluginErrorDialog -------------------------------------------------------------- #
class QgsPluginInstallerPluginErrorDialog(QDialog, Ui_QgsPluginInstallerPluginErrorDialog):
# ----------------------------------------- #
def __init__(self, parent, errorMessage):
QDialog.__init__(self, parent)
self.setupUi(self)
if not errorMessage:
errorMessage = self.tr("No error message received. Try to restart QGIS and ensure the plugin isn't installed under different name. If it is, contact the plugin author and submit this issue, please.")
self.textBrowser.setText(errorMessage)
# --- /class QgsPluginInstallerPluginErrorDialog ------------------------------------------------------------- #
# --- class QgsPluginInstallerDialog ------------------------------------------------------------------------- #
class QgsPluginInstallerDialog(QDialog, Ui_QgsPluginInstallerDialog):
# ----------------------------------------- #
def __init__(self, parent, fl):
QDialog.__init__(self, parent, fl)
self.setupUi(self)
self.reposGroup = "/Qgis/plugin-repos"
self.connect(self.lineFilter, SIGNAL("textChanged (QString)"), self.filterChanged)
self.connect(self.comboFilter1, SIGNAL("currentIndexChanged (int)"), self.filterChanged)
self.connect(self.comboFilter2, SIGNAL("currentIndexChanged (int)"), self.filterChanged)
# grab the click on the treePlugins
self.connect(self.treePlugins, SIGNAL("itemSelectionChanged()"), self.treeClicked)
# buttons
self.connect(self.buttonInstall, SIGNAL("clicked()"), self.installPlugin)
self.connect(self.buttonUninstall, SIGNAL("clicked()"), self.uninstallPlugin)
self.buttonInstall.setEnabled(False)
self.buttonUninstall.setEnabled(False)
# repositories handling
self.connect(self.treeRepositories, SIGNAL("doubleClicked(QModelIndex)"), self.editRepository)
self.connect(self.buttonFetchRepositories, SIGNAL("clicked()"), self.addKnownRepositories)
self.connect(self.buttonAddRep, SIGNAL("clicked()"), self.addRepository)
self.connect(self.buttonEditRep, SIGNAL("clicked()"), self.editRepository)
self.connect(self.buttonDeleteRep, SIGNAL("clicked()"), self.deleteRepository)
# checkingOnStart checkbox
self.connect(self.checkUpdates, SIGNAL("stateChanged (int)"), self.ChangeCheckingPolicy)
if repositories.checkingOnStart():
self.checkUpdates.setCheckState(Qt.Checked)
else:
self.checkUpdates.setCheckState(Qt.Unchecked)
self.populateMostWidgets()
# ----------------------------------------- #
def getAllAvailablePlugins(self):
""" repopulate the mPlugins dict """
repositories.load()
plugins.clear()
for key in repositories.allEnabled():
repositories.requestFetching(key)
if repositories.fetchingInProgress():
self.fetchDlg = QgsPluginInstallerFetchingDialog(self)
self.fetchDlg.exec_()
del self.fetchDlg
for key in repositories.all():
repositories.killConnection(key)
# display error messages for every unavailable reposioty, except the case if all repositories are unavailable!
if repositories.allUnavailable() and repositories.allUnavailable() != repositories.allEnabled():
for key in repositories.allUnavailable():
QMessageBox.warning(self, self.tr("QGIS Python Plugin Installer"), self.tr("Error reading repository: ") + key + "\n" + repositories.all()[key]["error"])
# ----------------------------------------- #
def populateMostWidgets(self):
self.comboFilter1.clear()
self.comboFilter1.addItem(self.tr("all repositories"))
self.treeRepositories.clear()
for key in repositories.all():
a = QTreeWidgetItem(self.treeRepositories)
a.setText(1,key)
a.setText(2,repositories.all()[key]["url"])
if repositories.all()[key]["enabled"] and repositories.all()[key]["valid"]:
if repositories.all()[key]["state"] == 2:
a.setText(0,self.tr("connected"))
a.setIcon(0,QIcon(":/plugins/installer/repoConnected.png"))
a.setToolTip(0,self.tr("This repository is connected"))
self.comboFilter1.addItem(key)
else:
a.setText(0,self.tr("unavailable"))
a.setIcon(0,QIcon(":/plugins/installer/repoUnavailable.png"))
a.setToolTip(0,self.tr("This repository is enabled, but unavailable"))
self.comboFilter1.addItem(key)
else:
a.setText(0,self.tr("disabled"))
a.setIcon(0,QIcon(":/plugins/installer/repoDisabled.png"))
if repositories.all()[key]["valid"]:
a.setToolTip(0,self.tr("This repository is disabled"))
else:
a.setToolTip(0,self.tr("This repository is blocked due to incompatibility with your QGIS version"))
a.setDisabled(True)
for i in [0,1,2]:
self.treeRepositories.resizeColumnToContents(i)
self.comboFilter1.addItem(self.tr("orphans"))
# filling the status filter comboBox
self.comboFilter2.clear()
self.comboFilter2.addItem(self.tr("any status"))
self.comboFilter2.addItem(self.tr("not installed"))
self.comboFilter2.addItem(self.tr("installed"))
if plugins.isThereAnythingNew():
self.comboFilter2.addItem(self.tr("upgradeable and news"))
# ----------------------------------------- #
def filterChanged(self,i):
""" one of the filter widgets has been changed """
self.populatePluginTree()
# ----------------------------------------- #
def filterCheck(self,plugin):
""" the filter for the pluginsTree """
if self.comboFilter1.currentIndex() != 0 and self.comboFilter1.currentText() != self.tr("orphans"):
if self.comboFilter1.currentText() != plugin["repository"]:
return False
elif self.comboFilter1.currentText() == self.tr("orphans"):
if plugin["status"] != "orphan":
return False
if self.comboFilter2.currentIndex() == 1 and not plugin["status"] in ["not installed","new"]:
return False
if self.comboFilter2.currentIndex() == 2 and not plugin["status"] in ["installed","upgradeable","newer","orphan","invalid"]:
return False
if self.comboFilter2.currentIndex() == 3 and not plugin["status"] in ["upgradeable","new"]:
return False
if self.lineFilter.text() == "":
return True
else:
for i in ["name","version_inst","version_avail","desc_repo","desc_local","author","status","repository"]:
item = str(plugin[i]).upper()
if item != None:
if item.find(self.lineFilter.text().toUpper()) > -1:
return True
return False
# ----------------------------------------- #
def populatePluginTree(self):
""" fill up the pluginTree """
descrip={"not installed" : self.tr("This plugin is not installed"),
"installed" : self.tr("This plugin is installed"),
"upgradeable" : self.tr("This plugin is installed, but there is an updated version available"),
"orphan" : self.tr("This plugin is installed, but I can't find it in any enabled repository"),
"new" : self.tr("This plugin is not installed and is seen first time"),
"newer" : self.tr("This plugin is installed and is newer than its version available in a repository"),
"invalid" : self.tr("This plugin seems to be invalid or have unfulfilled dependencies\nIt has been installed, but can't be loaded")}
status ={"not installed" : self.tr("not installed"),
"installed" : self.tr("installed"),
"upgradeable" : self.tr("upgradeable"),
"orphan" : self.tr("installed"),
"new" : self.tr("new!"),
"newer" : self.tr("installed"),
"invalid" : self.tr("invalid")}
order = ["invalid","upgradeable","new","not installed","installed","orphan","newer"]
def addItem(p):
if self.filterCheck(p):
statusTip = descrip[p["status"]]
if p["read-only"]:
statusTip += "\n" + self.tr("Note that it's installed in the read-only location and you can't uninstall it")
if p["status"] == "upgradeable":
ver = p["version_inst"] + " -> " + p["version_avail"]
elif p["status"] == "newer":
ver = p["version_inst"] + " (" + p["version_avail"] + ")"
elif p["status"] in ["not installed", "new", "invalid"]:
ver = p["version_avail"]
else:
ver = p["version_inst"]
if p["status"] in ["upgradeable","newer"]:
vd = self.tr("installed version") + ": " + p["version_inst"] + "\n" + self.tr("available version") + ": " + p["version_avail"]
elif p["status"] in ["not installed", "new"]:
vd = self.tr("available version") + ": " + p["version_avail"]
elif p["status"] == "installed":
vd = self.tr("installed version") + ": " + p["version_inst"] + "\n" + self.tr("That's the newest available version.")
elif p["status"] == "orphan":
vd = self.tr("installed version") + ": " + p["version_inst"] + "\n" + self.tr("There is no version available for download.")
else:
vd = ""
if p["status"] == "invalid":
p["desc_local"] = self.tr("This plugin seems to be invalid or have unfulfilled dependencies")
p["desc_repo"] = self.tr("This plugin seems to be invalid or have unfulfilled dependencies\nIt has been installed, but can't be loaded")
if p["status"] == "orphan":
if p["read-only"]:
url = unicode(QgsApplication.pkgDataPath(),'utf-8') + "/python/plugins/" + p["localdir"]
else:
url = unicode(QgsApplication.qgisSettingsDirPath(),'utf-8') + "/python/plugins/" + p["localdir"]
repository = self.tr("only locally available")
else:
url = p["url"]
repository = p["repository"]
if not p["desc_local"]:
p["desc_local"] = p["desc_repo"]
a = QTreeWidgetItem(self.treePlugins)
a.setText(0,status[p["status"]])
a.setToolTip(0,statusTip)
a.setText(1,p["name"])
a.setText(2,ver)
a.setToolTip(2,vd)
a.setText(3,p["desc_local"])
a.setToolTip(3, p["desc_repo"])
a.setText(4,p["author"])
if p["homepage"]:
a.setToolTip(4,p["homepage"])
else:
a.setToolTip(4,"")
a.setText(5,repository)
a.setToolTip(5,url)
# set fonts and colours
for i in [0,1,2,3,4,5]:
if p["status"] == "invalid":
a.setForeground(i,QBrush(QColor(Qt.red)))
if p["status"] in ["new","upgradeable","invalid"]:
font = QFont()
font.setWeight(QFont.Bold)
a.setFont(i,font)
# -------- #
if not plugins.all():
return
self.treePlugins.clear()
for i in order:
for p in plugins.all().values():
if p["status"] == i:
addItem(p)
# resize the columns
for i in [0,1,2,3,4,5]:
self.treePlugins.resizeColumnToContents(i)
for i in [0,1,2,4,5]:
if self.treePlugins.columnWidth(i) > 260:
self.treePlugins.setColumnWidth(i, 260)
if self.treePlugins.columnWidth(3) > 560:
self.treePlugins.setColumnWidth(3, 560)
# initially, keep order of inserting
self.treePlugins.sortItems(100,Qt.AscendingOrder)
# ----------------------------------------- #
def treeClicked(self):
""" the pluginsTree has been clicked """
buttons={"not installed":(True,False,self.tr("Install plugin")),
"installed":(True,True,self.tr("Reinstall plugin")),
"upgradeable":(True,True,self.tr("Upgrade plugin",)),
"orphan":(False,True,self.tr("Install/upgrade plugin")),
"new":(True, False,self.tr("Install plugin")),
"newer":(True,True,self.tr("Downgrade plugin")),
"invalid":(False,True,self.tr("Reinstall plugin"))}
self.buttonInstall.setEnabled(False)
self.buttonInstall.setText(self.tr("Install/upgrade plugin"))
self.buttonUninstall.setEnabled(False)
item = self.treePlugins.currentItem()
if not item:
return
key = plugins.firstByName(item.text(1))
if not key:
return
plugin = plugins.all()[key]
if not plugin:
return
self.buttonInstall.setEnabled(buttons[plugin["status"]][0])
self.buttonUninstall.setEnabled(buttons[plugin["status"]][1])
self.buttonInstall.setText(buttons[plugin["status"]][2])
if plugin["read-only"]:
self.buttonUninstall.setEnabled(False)
# ----------------------------------------- #
def installPlugin(self):
""" install currently selected plugin """
if not self.treePlugins.currentItem():
return
key = plugins.firstByName(self.treePlugins.currentItem().text(1))
plugin = plugins.all()[key]
if not plugin:
return
dlg = QgsPluginInstallerInstallingDialog(self,plugin)
dlg.exec_()
if dlg.result():
infoString = (self.tr("Plugin installation failed"), dlg.result())
else:
try:
exec ("sys.path_importer_cache.clear()")
exec ("del sys.modules[%s]" % plugin["localdir"]) # remove old version if exist
except:
pass
try:
exec ("import %s" % plugin["localdir"])
exec ("reload (%s)" % plugin["localdir"])
if plugin["status"] == "not installed" or plugin["status"] == "new":
infoString = (self.tr("Plugin installed successfully"), self.tr("Python plugin installed.\nYou have to enable it in the Plugin Manager."))
else:
infoString = (self.tr("Plugin installed successfully"),self.tr("Python plugin reinstalled.\nYou have to restart Quantum GIS to reload it."))
except Exception, error:
dlg = QgsPluginInstallerPluginErrorDialog(self,error.message)
dlg.exec_()
if dlg.result():
pluginDir = unicode(QFileInfo(QgsApplication.qgisUserDbFilePath()).path()+"/python/plugins/"+ str(plugin["localdir"]))
result = removeDir(pluginDir)
if result:
QMessageBox.warning(self, self.tr("Plugin uninstall failed"), result)
plugins.updatePlugin(key, False)
self.populateMostWidgets()
self.populatePluginTree()
return
plugins.updatePlugin(key, False)
self.populateMostWidgets()
self.populatePluginTree()
QMessageBox.information(self, infoString[0], infoString[1])
# ----------------------------------------- #
def uninstallPlugin(self):
""" uninstall currently selected plugin """
if not self.treePlugins.currentItem():
return
key = plugins.firstByName(self.treePlugins.currentItem().text(1))
plugin = plugins.all()[key]
if not plugin:
return
warning = self.tr("Are you sure you want to uninstall the plugin ") + plugin["name"] + "?"
if plugin["status"] == "orphan":
warning += "\n\n"+self.tr("Warning: this plugin isn't available in any accessible repository!")
if QMessageBox.warning(self, self.tr("QGIS Python Plugin Installer"), warning , QMessageBox.Yes, QMessageBox.No) == QMessageBox.No:
return
pluginDir = unicode(QFileInfo(QgsApplication.qgisUserDbFilePath()).path()+"/python/plugins/"+ str(plugin["localdir"]))
#print "Uninstalling plugin", plugin["name"], pluginDir
result = removeDir(pluginDir)
if result:
QApplication.restoreOverrideCursor()
QMessageBox.warning(self, self.tr("Plugin uninstall failed"), result)
else:
try:
exec ("del sys.modules[%s]" % plugin["localdir"])
except:
pass
plugins.setPluginData(key, "status", "not installed")
plugins.setPluginData(key, "version_inst", "")
plugins.setPluginData(key, "desc_local", "")
self.populatePluginTree()
QApplication.restoreOverrideCursor()
QMessageBox.information(self, self.tr("QGIS Python Plugin Installer"), self.tr("Plugin uninstalled successfully"))
# ----------------------------------------- #
def ChangeCheckingPolicy(self,policy):
if policy == Qt.Checked:
repositories.setCheckingOnStart(True)
else:
repositories.setCheckingOnStart(False)
# ----------------------------------------- #
def addKnownRepositories(self):
""" update list of known repositories - in the future it will be replaced with an online fetching """
#print "add known repositories"
message = "You are going to add some plugin repositories not authotized nor supported by the QGIS team, however provided by folks associated with us.\n"
message += "Plugin authors generally make efforts to make their works useful and safe, but we can't assume any responsibility for them. FEEL WARNED!"
if QMessageBox.question(self, self.tr("QGIS Python Plugin Installer"), self.tr(message), QMessageBox.Ok, QMessageBox.Abort) == QMessageBox.Ok:
repositories.addKnownRepos()
# refresh lists and populate widgets
QApplication.setOverrideCursor(Qt.WaitCursor)
self.getAllAvailablePlugins()
self.populateMostWidgets()
self.populatePluginTree()
QApplication.restoreOverrideCursor()
# ----------------------------------------- #
def addRepository(self):
""" add repository button has been clicked """
#print "add"
dlg = QgsPluginInstallerRepositoryDialog(self)
dlg.checkBoxEnabled.setCheckState(Qt.Checked)
if not dlg.exec_():
return
for i in repositories.all().values():
if dlg.editURL.text() == i["url"]:
QMessageBox.warning(self, self.tr("QGIS Python Plugin Installer"), self.tr("Unable to add another repository with the same URL!"))
return
settings = QSettings()
settings.beginGroup(self.reposGroup)
reposName = dlg.editName.text()
reposURL = dlg.editURL.text()
if repositories.all().has_key(reposName):
reposName = reposName + "(2)"
#print "name: "+reposName
#print "url: "+reposURL
# add to settings
settings.setValue(reposName+"/url", QVariant(reposURL))
settings.setValue(reposName+"/enabled", QVariant(bool(dlg.checkBoxEnabled.checkState())))
# refresh lists and populate widgets
QApplication.setOverrideCursor(Qt.WaitCursor)
self.getAllAvailablePlugins()
self.populateMostWidgets()
self.populatePluginTree()
QApplication.restoreOverrideCursor()
# ----------------------------------------- #
def editRepository(self):
""" edit repository button has been clicked """
#print "edit"
checkState={False:Qt.Unchecked,True:Qt.Checked}
current = self.treeRepositories.currentItem()
if current == None:
return
reposName = current.text(1)
dlg = QgsPluginInstallerRepositoryDialog(self)
dlg.editName.setText(reposName)
dlg.editURL.setText(repositories.all()[reposName]["url"])
dlg.checkBoxEnabled.setCheckState(checkState[repositories.all()[reposName]["enabled"]])
if repositories.all()[reposName]["valid"]:
dlg.checkBoxEnabled.setEnabled(True)
dlg.labelInfo.setText("")
else:
dlg.checkBoxEnabled.setEnabled(False)
dlg.labelInfo.setText(self.tr("This repository is blocked due to incompatibility with your QGIS version"))
dlg.labelInfo.setFrameShape(QFrame.Box)
if not dlg.exec_():
return # nothing to do if cancelled
for i in repositories.all().values():
if dlg.editURL.text() == i["url"] and dlg.editURL.text() != repositories.all()[reposName]["url"]:
QMessageBox.warning(self, self.tr("QGIS Python Plugin Installer"), self.tr("Unable to add another repository with the same URL!"))
return
# delete old repo from QSettings and create new one
settings = QSettings()
settings.beginGroup(self.reposGroup)
settings.remove(reposName)
newName = dlg.editName.text()
if repositories.all().has_key(newName) and newName != reposName:
newName = newName + "(2)"
settings.setValue(newName+"/url", QVariant(dlg.editURL.text()))
settings.setValue(newName+"/enabled", QVariant(bool(dlg.checkBoxEnabled.checkState())))
if dlg.editURL.text() == repositories.all()[reposName]["url"] and dlg.checkBoxEnabled.checkState() == checkState[repositories.all()[reposName]["enabled"]]:
repositories.rename(reposName, newName)
self.populateMostWidgets()
return # nothing else to do if only repository name was changed
# refresh lists and populate widgets
QApplication.setOverrideCursor(Qt.WaitCursor)
self.getAllAvailablePlugins()
self.populateMostWidgets()
self.populatePluginTree()
QApplication.restoreOverrideCursor()
# ----------------------------------------- #
def deleteRepository(self):
""" delete repository button has been clicked """
#print "delete"
current = self.treeRepositories.currentItem()
if current == None:
return
warning = self.tr("Are you sure you want to remove the repository") + "\n" + current.text(1) + "?"
if QMessageBox.warning(self, self.tr("QGIS Python Plugin Installer"), warning , QMessageBox.Yes, QMessageBox.No) == QMessageBox.No:
return
reposName = current.text(1)
settings = QSettings()
settings.beginGroup(self.reposGroup)
# delete from settings
settings.remove(reposName)
# refresh lists and populate widgets
QApplication.setOverrideCursor(Qt.WaitCursor)
self.getAllAvailablePlugins()
self.populateMostWidgets()
self.populatePluginTree()
QApplication.restoreOverrideCursor()
# ----------------------------------------- #
def reject(self):
""" update the list of seen plugins before exit (both 'done' and 'x' buttons emit 'reject' signal) """
plugins.updateSeenPluginsList()
QDialog.reject(self)
# --- /class QgsPluginInstallerDialog ------------------------------------------------------------------------ #

View File

@ -1,5 +1,8 @@
# -*- coding: utf-8 -*-
"""
Copyright (C) 2008 Matthew Perry
Copyright (C) 2008 Borys Jurgiel
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
@ -12,36 +15,108 @@ Copyright (C) 2008 Matthew Perry
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
from dialog import InstallerPluginGui
import resources
from installer_gui import *
from installer_data import *
import resources_rc
class InstallerPlugin:
# ----------------------------------------- #
def __init__(self, iface):
# save reference to the QGIS interface
self.iface = iface
if str(QGis.qgisVersion)[0] == "0": # old plugin API
self.mainWindow = self.iface.getMainWindow
else: # new plugin API
self.mainWindow = self.iface.mainWindow
# ----------------------------------------- #
def initGui(self):
# create action that will start plugin configuration
self.action = QAction(QIcon(":/plugins/installer/icon.xpm"), "Install plugins", self.iface.mainWindow())
self.action.setWhatsThis("Plugin Installer")
""" create action that will start plugin window and then add it to menu """
self.action = QAction(QIcon(":/plugins/installer/PluginInstaller.png"), QCoreApplication.translate("QgsPluginInstaller","Plugin Installer..."), self.mainWindow())
self.action.setWhatsThis(QCoreApplication.translate("QgsPluginInstaller","Install more plugins from remote repositories"))
self.action.setStatusTip(QCoreApplication.translate("QgsPluginInstaller","Install more plugins from remote repositories"))
if str(QGis.qgisVersion)[0] == "0":
nextAction = self.mainWindow().menuBar().actions()[4].menu().actions()[1]
self.mainWindow().menuBar().actions()[4].menu().insertAction(nextAction,self.action)
else:
nextAction = self.iface.actionPluginSeparator1()
self.iface.pluginMenu().insertAction(nextAction,self.action)
QObject.connect(self.action, SIGNAL("activated()"), self.run)
self.statusLabel = None
repositories.load()
plugins.clear()
if repositories.checkingOnStart():
self.statusLabel = QLabel(QCoreApplication.translate("QgsPluginInstaller","Looking for new plugins..."), self.mainWindow().statusBar())
self.mainWindow().statusBar().insertPermanentWidget(0,self.statusLabel)
QObject.connect(self.statusLabel, SIGNAL("linkActivated (QString)"), self.run)
QObject.connect(repositories, SIGNAL("checkingDone()"), self.checkingDone)
for key in repositories.allEnabled():
repositories.requestFetching(key)
else:
for key in repositories.allEnabled():
repositories.setRepositoryData(key,"state",3)
# ----------------------------------------- #
def checkingDone(self):
""" display the notify label if any updates or news available """
if not self.statusLabel:
return
# look for news in the repositories
plugins.markNews()
status = ""
# first check for news
for key in plugins.all():
if plugins.all()[key]["status"] == "new":
status = QCoreApplication.translate("QgsPluginInstaller","There is a new plugin available")
# then check for updates (and eventually overwrite status)
for key in plugins.all():
if plugins.all()[key]["status"] == "upgradeable":
status = QCoreApplication.translate("QgsPluginInstaller","There is a plugin update available")
# finally set the notify label
if status:
self.statusLabel.setText(u' <a href="#">%s</a> ' % status)
else:
self.mainWindow().statusBar().removeWidget(self.statusLabel)
self.statusLabel = None
# add toolbar button and menu item
self.iface.addToolBarIcon(self.action)
self.iface.addPluginToMenu("&Plugin Installer", self.action)
# ----------------------------------------- #
def unload(self):
# remove the plugin menu item and icon
self.iface.removePluginMenu("&Plugin Installer",self.action)
self.iface.removeToolBarIcon(self.action)
""" remove the menu item and notify label """
self.mainWindow().menuBar().actions()[4].menu().removeAction(self.action)
if self.statusLabel:
self.mainWindow().statusBar().removeWidget(self.statusLabel)
# ----------------------------------------- #
def run(self):
# create and show a configuration dialog
def run(self, * params):
""" create and show a configuration dialog """
QApplication.setOverrideCursor(Qt.WaitCursor)
if self.statusLabel:
self.mainWindow().statusBar().removeWidget(self.statusLabel)
self.statusLabel = None
for key in repositories.all():
if repositories.all()[key]["state"] == 3: # if state = 3 (error), try to fetch once again
repositories.requestFetching(key)
if repositories.fetchingInProgress():
self.fetchDlg = QgsPluginInstallerFetchingDialog(self.mainWindow())
self.fetchDlg.exec_()
del self.fetchDlg
for key in repositories.all():
repositories.killConnection(key)
QApplication.restoreOverrideCursor()
# display error messages for every unavailable reposioty, except the case if all repositories are unavailable!
if repositories.allUnavailable() and repositories.allUnavailable() != repositories.allEnabled():
for key in repositories.allUnavailable():
QMessageBox.warning(self.mainWindow(), QCoreApplication.translate("QgsPluginInstaller","QGIS Python Plugin Installer"), QCoreApplication.translate("QgsPluginInstaller","Error reading repository:") + u' %s\n%s' % (key,repositories.all()[key]["error"]))
flags = Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMaximizeButtonHint
self.gui = InstallerPluginGui(self.iface.mainWindow(),flags)
self.gui.show()
self.guiDlg = QgsPluginInstallerDialog(self.mainWindow(),flags)
self.guiDlg.show()

View File

@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'installingbase.ui'
#
# Created: Sun Sep 7 16:22:38 2008
# by: PyQt4 UI code generator 4.3
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_QgsPluginInstallerInstallingDialog(object):
def setupUi(self, QgsPluginInstallerInstallingDialog):
QgsPluginInstallerInstallingDialog.setObjectName("QgsPluginInstallerInstallingDialog")
QgsPluginInstallerInstallingDialog.resize(QtCore.QSize(QtCore.QRect(0,0,520,175).size()).expandedTo(QgsPluginInstallerInstallingDialog.minimumSizeHint()))
QgsPluginInstallerInstallingDialog.setWindowIcon(QtGui.QIcon(":/plugins/installer/qgis-icon.png"))
self.gridlayout = QtGui.QGridLayout(QgsPluginInstallerInstallingDialog)
self.gridlayout.setObjectName("gridlayout")
spacerItem = QtGui.QSpacerItem(502,16,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.MinimumExpanding)
self.gridlayout.addItem(spacerItem,0,0,1,1)
self.hboxlayout = QtGui.QHBoxLayout()
self.hboxlayout.setObjectName("hboxlayout")
self.label = QtGui.QLabel(QgsPluginInstallerInstallingDialog)
self.label.setObjectName("label")
self.hboxlayout.addWidget(self.label)
self.labelName = QtGui.QLabel(QgsPluginInstallerInstallingDialog)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.labelName.sizePolicy().hasHeightForWidth())
self.labelName.setSizePolicy(sizePolicy)
self.labelName.setObjectName("labelName")
self.hboxlayout.addWidget(self.labelName)
self.gridlayout.addLayout(self.hboxlayout,1,0,1,1)
self.labelState = QtGui.QLabel(QgsPluginInstallerInstallingDialog)
self.labelState.setObjectName("labelState")
self.gridlayout.addWidget(self.labelState,2,0,1,1)
self.progressBar = QtGui.QProgressBar(QgsPluginInstallerInstallingDialog)
self.progressBar.setMaximum(100)
self.progressBar.setProperty("value",QtCore.QVariant(0))
self.progressBar.setAlignment(QtCore.Qt.AlignHCenter)
self.progressBar.setTextDirection(QtGui.QProgressBar.TopToBottom)
self.progressBar.setObjectName("progressBar")
self.gridlayout.addWidget(self.progressBar,3,0,1,1)
spacerItem1 = QtGui.QSpacerItem(502,16,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Fixed)
self.gridlayout.addItem(spacerItem1,4,0,1,1)
self.buttonBox = QtGui.QDialogButtonBox(QgsPluginInstallerInstallingDialog)
self.buttonBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.buttonBox.setContextMenuPolicy(QtCore.Qt.NoContextMenu)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Abort)
self.buttonBox.setCenterButtons(True)
self.buttonBox.setObjectName("buttonBox")
self.gridlayout.addWidget(self.buttonBox,5,0,1,1)
self.retranslateUi(QgsPluginInstallerInstallingDialog)
QtCore.QMetaObject.connectSlotsByName(QgsPluginInstallerInstallingDialog)
def retranslateUi(self, QgsPluginInstallerInstallingDialog):
QgsPluginInstallerInstallingDialog.setWindowTitle(QtGui.QApplication.translate("QgsPluginInstallerInstallingDialog", "QGIS Python Plugin Installer", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("QgsPluginInstallerInstallingDialog", "Installing plugin:", None, QtGui.QApplication.UnicodeUTF8))
self.labelState.setText(QtGui.QApplication.translate("QgsPluginInstallerInstallingDialog", "Connecting...", None, QtGui.QApplication.UnicodeUTF8))
import resources_rc

View File

@ -0,0 +1,124 @@
<ui version="4.0" >
<author>Matthew Perry, Borys Jurgiel</author>
<class>QgsPluginInstallerInstallingDialog</class>
<widget class="QDialog" name="QgsPluginInstallerInstallingDialog" >
<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>
<property name="windowIcon" >
<iconset resource="resources.qrc" >:/plugins/installer/qgis-icon.png</iconset>
</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>
<resources>
<include location="resources.qrc" />
</resources>
<connections/>
</ui>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -0,0 +1,68 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'pluginerrorbase.ui'
#
# Created: Sun Sep 7 16:22:47 2008
# by: PyQt4 UI code generator 4.3
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_QgsPluginInstallerPluginErrorDialog(object):
def setupUi(self, QgsPluginInstallerPluginErrorDialog):
QgsPluginInstallerPluginErrorDialog.setObjectName("QgsPluginInstallerPluginErrorDialog")
QgsPluginInstallerPluginErrorDialog.resize(QtCore.QSize(QtCore.QRect(0,0,521,383).size()).expandedTo(QgsPluginInstallerPluginErrorDialog.minimumSizeHint()))
QgsPluginInstallerPluginErrorDialog.setMinimumSize(QtCore.QSize(480,300))
QgsPluginInstallerPluginErrorDialog.setWindowIcon(QtGui.QIcon(":/plugins/installer/qgis-icon.png"))
self.gridlayout = QtGui.QGridLayout(QgsPluginInstallerPluginErrorDialog)
self.gridlayout.setObjectName("gridlayout")
self.label = QtGui.QLabel(QgsPluginInstallerPluginErrorDialog)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
self.label.setSizePolicy(sizePolicy)
self.label.setWordWrap(True)
self.label.setOpenExternalLinks(True)
self.label.setObjectName("label")
self.gridlayout.addWidget(self.label,1,0,1,1)
self.textBrowser = QtGui.QTextBrowser(QgsPluginInstallerPluginErrorDialog)
self.textBrowser.setMinimumSize(QtCore.QSize(0,0))
self.textBrowser.setFocusPolicy(QtCore.Qt.NoFocus)
self.textBrowser.setObjectName("textBrowser")
self.gridlayout.addWidget(self.textBrowser,2,0,1,1)
spacerItem = QtGui.QSpacerItem(503,10,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Fixed)
self.gridlayout.addItem(spacerItem,3,0,1,1)
self.label1 = QtGui.QLabel(QgsPluginInstallerPluginErrorDialog)
self.label1.setFrameShape(QtGui.QFrame.NoFrame)
self.label1.setFrameShadow(QtGui.QFrame.Plain)
self.label1.setWordWrap(True)
self.label1.setObjectName("label1")
self.gridlayout.addWidget(self.label1,4,0,1,1)
self.buttonBox = QtGui.QDialogButtonBox(QgsPluginInstallerPluginErrorDialog)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.No|QtGui.QDialogButtonBox.NoButton|QtGui.QDialogButtonBox.Yes)
self.buttonBox.setObjectName("buttonBox")
self.gridlayout.addWidget(self.buttonBox,6,0,1,1)
spacerItem1 = QtGui.QSpacerItem(10,10,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Fixed)
self.gridlayout.addItem(spacerItem1,0,0,1,1)
self.retranslateUi(QgsPluginInstallerPluginErrorDialog)
QtCore.QObject.connect(self.buttonBox,QtCore.SIGNAL("rejected()"),QgsPluginInstallerPluginErrorDialog.reject)
QtCore.QObject.connect(self.buttonBox,QtCore.SIGNAL("accepted()"),QgsPluginInstallerPluginErrorDialog.accept)
QtCore.QMetaObject.connectSlotsByName(QgsPluginInstallerPluginErrorDialog)
def retranslateUi(self, QgsPluginInstallerPluginErrorDialog):
QgsPluginInstallerPluginErrorDialog.setWindowTitle(QtGui.QApplication.translate("QgsPluginInstallerPluginErrorDialog", "Error loading plugin", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("QgsPluginInstallerPluginErrorDialog", "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 <a href=\"http://lists.osgeo.org/mailman/listinfo/qgis-user\">QGIS users group</a> and try to solve the problem. If not, you can just uninstall it. Here is the error message below:", None, QtGui.QApplication.UnicodeUTF8))
self.label1.setText(QtGui.QApplication.translate("QgsPluginInstallerPluginErrorDialog", "Do you want to uninstall this plugin now? If you\'re unsure, probably you would like to do this.", None, QtGui.QApplication.UnicodeUTF8))
import resources_rc

View File

@ -0,0 +1,155 @@
<ui version="4.0" >
<author>Matthew Perry, Borys Jurgiel</author>
<class>QgsPluginInstallerPluginErrorDialog</class>
<widget class="QDialog" name="QgsPluginInstallerPluginErrorDialog" >
<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>
<property name="windowIcon" >
<iconset resource="resources.qrc" >:/plugins/installer/qgis-icon.png</iconset>
</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>
<resources>
<include location="resources.qrc" />
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QgsPluginInstallerPluginErrorDialog</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>QgsPluginInstallerPluginErrorDialog</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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

View File

@ -0,0 +1,123 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'repositorybase.ui'
#
# Created: Tue Sep 9 00:09:51 2008
# by: PyQt4 UI code generator 4.3
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
class Ui_QgsPluginInstallerRepositoryDetailsDialog(object):
def setupUi(self, QgsPluginInstallerRepositoryDetailsDialog):
QgsPluginInstallerRepositoryDetailsDialog.setObjectName("QgsPluginInstallerRepositoryDetailsDialog")
QgsPluginInstallerRepositoryDetailsDialog.resize(QtCore.QSize(QtCore.QRect(0,0,522,191).size()).expandedTo(QgsPluginInstallerRepositoryDetailsDialog.minimumSizeHint()))
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred,QtGui.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(QgsPluginInstallerRepositoryDetailsDialog.sizePolicy().hasHeightForWidth())
QgsPluginInstallerRepositoryDetailsDialog.setSizePolicy(sizePolicy)
QgsPluginInstallerRepositoryDetailsDialog.setWindowIcon(QtGui.QIcon(":/plugins/installer/qgis-icon.png"))
self.gridlayout = QtGui.QGridLayout(QgsPluginInstallerRepositoryDetailsDialog)
self.gridlayout.setObjectName("gridlayout")
self.label = QtGui.QLabel(QgsPluginInstallerRepositoryDetailsDialog)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,QtGui.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
self.label.setSizePolicy(sizePolicy)
self.label.setObjectName("label")
self.gridlayout.addWidget(self.label,0,0,1,1)
spacerItem = QtGui.QSpacerItem(16,27,QtGui.QSizePolicy.Fixed,QtGui.QSizePolicy.Minimum)
self.gridlayout.addItem(spacerItem,0,1,1,1)
self.editName = QtGui.QLineEdit(QgsPluginInstallerRepositoryDetailsDialog)
self.editName.setObjectName("editName")
self.gridlayout.addWidget(self.editName,0,2,1,2)
self.label_2 = QtGui.QLabel(QgsPluginInstallerRepositoryDetailsDialog)
self.label_2.setObjectName("label_2")
self.gridlayout.addWidget(self.label_2,1,0,1,1)
self.editURL = QtGui.QLineEdit(QgsPluginInstallerRepositoryDetailsDialog)
self.editURL.setObjectName("editURL")
self.gridlayout.addWidget(self.editURL,1,2,1,2)
self.checkBoxEnabled = QtGui.QCheckBox(QgsPluginInstallerRepositoryDetailsDialog)
self.checkBoxEnabled.setEnabled(True)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.checkBoxEnabled.sizePolicy().hasHeightForWidth())
self.checkBoxEnabled.setSizePolicy(sizePolicy)
self.checkBoxEnabled.setChecked(False)
self.checkBoxEnabled.setObjectName("checkBoxEnabled")
self.gridlayout.addWidget(self.checkBoxEnabled,2,2,1,1)
spacerItem1 = QtGui.QSpacerItem(351,23,QtGui.QSizePolicy.Fixed,QtGui.QSizePolicy.Minimum)
self.gridlayout.addItem(spacerItem1,2,3,1,1)
self.labelInfo = QtGui.QLabel(QgsPluginInstallerRepositoryDetailsDialog)
self.labelInfo.setEnabled(True)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.labelInfo.sizePolicy().hasHeightForWidth())
self.labelInfo.setSizePolicy(sizePolicy)
palette = QtGui.QPalette()
brush = QtGui.QBrush(QtGui.QColor(175,0,0))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Active,QtGui.QPalette.WindowText,brush)
brush = QtGui.QBrush(QtGui.QColor(175,0,0))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Inactive,QtGui.QPalette.WindowText,brush)
brush = QtGui.QBrush(QtGui.QColor(128,128,128))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Disabled,QtGui.QPalette.WindowText,brush)
self.labelInfo.setPalette(palette)
font = QtGui.QFont()
font.setWeight(75)
font.setBold(True)
self.labelInfo.setFont(font)
self.labelInfo.setFrameShape(QtGui.QFrame.NoFrame)
self.labelInfo.setObjectName("labelInfo")
self.gridlayout.addWidget(self.labelInfo,3,2,1,2)
self.buttonBox = QtGui.QDialogButtonBox(QgsPluginInstallerRepositoryDetailsDialog)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.NoButton|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.gridlayout.addWidget(self.buttonBox,5,0,1,4)
self.retranslateUi(QgsPluginInstallerRepositoryDetailsDialog)
QtCore.QObject.connect(self.buttonBox,QtCore.SIGNAL("accepted()"),QgsPluginInstallerRepositoryDetailsDialog.accept)
QtCore.QObject.connect(self.buttonBox,QtCore.SIGNAL("rejected()"),QgsPluginInstallerRepositoryDetailsDialog.reject)
QtCore.QMetaObject.connectSlotsByName(QgsPluginInstallerRepositoryDetailsDialog)
def retranslateUi(self, QgsPluginInstallerRepositoryDetailsDialog):
QgsPluginInstallerRepositoryDetailsDialog.setWindowTitle(QtGui.QApplication.translate("QgsPluginInstallerRepositoryDetailsDialog", "Repository details", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("QgsPluginInstallerRepositoryDetailsDialog", "Name:", None, QtGui.QApplication.UnicodeUTF8))
self.editName.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerRepositoryDetailsDialog", "Enter a name for the repository", None, QtGui.QApplication.UnicodeUTF8))
self.editName.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerRepositoryDetailsDialog", "Enter a name for the repository", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("QgsPluginInstallerRepositoryDetailsDialog", "URL:", None, QtGui.QApplication.UnicodeUTF8))
self.editURL.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerRepositoryDetailsDialog", "Enter the repository URL, beginning with \"http://\"", None, QtGui.QApplication.UnicodeUTF8))
self.editURL.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerRepositoryDetailsDialog", "Enter the repository URL, beginning with \"http://\"", None, QtGui.QApplication.UnicodeUTF8))
self.checkBoxEnabled.setToolTip(QtGui.QApplication.translate("QgsPluginInstallerRepositoryDetailsDialog", "Enable or disable the repository (disabled repositories will be omitted)", None, QtGui.QApplication.UnicodeUTF8))
self.checkBoxEnabled.setWhatsThis(QtGui.QApplication.translate("QgsPluginInstallerRepositoryDetailsDialog", "Enable or disable the repository (disabled repositories will be omitted)", None, QtGui.QApplication.UnicodeUTF8))
self.checkBoxEnabled.setText(QtGui.QApplication.translate("QgsPluginInstallerRepositoryDetailsDialog", "Enabled", None, QtGui.QApplication.UnicodeUTF8))
self.labelInfo.setText(QtGui.QApplication.translate("QgsPluginInstallerRepositoryDetailsDialog", "[place for a warning message]", None, QtGui.QApplication.UnicodeUTF8))
import resources_rc

View File

@ -0,0 +1,243 @@
<ui version="4.0" >
<author>Matthew Perry, Borys Jurgiel</author>
<class>QgsPluginInstallerRepositoryDetailsDialog</class>
<widget class="QDialog" name="QgsPluginInstallerRepositoryDetailsDialog" >
<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="windowIcon" >
<iconset resource="resources.qrc" >:/plugins/installer/qgis-icon.png</iconset>
</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>[place for a warning message]</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>
<resources>
<include location="resources.qrc" />
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QgsPluginInstallerRepositoryDetailsDialog</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>QgsPluginInstallerRepositoryDetailsDialog</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>

View File

@ -1,5 +1,9 @@
<RCC>
<qresource prefix="/plugins/installer" >
<file>icon.xpm</file>
<qresource prefix="/plugins/installer">
<file>PluginInstaller.png</file>
<file>qgis-icon.png</file>
<file>repoDisabled.png</file>
<file>repoUnavailable.png</file>
<file>repoConnected.png</file>
</qresource>
</RCC>

View File

@ -0,0 +1,580 @@
# -*- coding: utf-8 -*-
# Resource object code
#
# Created: ?r. wrz 3 18:43:47 2008
# by: The Resource Compiler for PyQt (Qt v4.3.2)
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore
qt_resource_data = "\
\x00\x00\x01\xe2\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x16\x00\x00\x00\x16\x08\x04\x00\x00\x00\x6e\xbd\xa4\xb0\
\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
\x02\x62\x4b\x47\x44\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09\x70\
\x48\x59\x73\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\
\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xd8\x07\x0f\x08\x30\x24\x35\
\xac\x7b\x3e\x00\x00\x01\x66\x49\x44\x41\x54\x28\xcf\xd5\xd3\x41\
\x6b\x13\x41\x00\x40\xe1\x6f\x76\x37\x89\x69\x2c\x26\xdb\xa6\x9a\
\x0a\x45\xb1\x07\x05\x7f\x59\x2f\x7a\xf7\xec\x59\xbc\xd8\x3f\x25\
\x14\x6f\x05\xa9\x58\xc4\x9a\x36\x34\x69\xac\x69\x9a\x6c\xb2\xeb\
\xc1\xa4\x6c\xe2\xd9\x83\x73\x98\x81\xe1\xf1\xe6\x31\xcc\xf0\xff\
\x8d\x00\xaf\xdf\x3e\x39\x88\x9a\xcb\xad\xe8\x6e\x0e\x82\xe9\xd5\
\xc9\x87\xf7\x6f\x4a\xf0\xbb\xfe\xb3\x56\x2c\x42\x24\x56\x5d\x80\
\xb1\x48\x64\xe2\xe3\xe0\x55\xfa\x07\x4e\x20\x6e\xd1\x46\x55\xaa\
\xa5\x82\xcc\xb5\x91\x20\x18\xaa\xb6\x56\xce\x2c\x64\x7e\x29\xec\
\x79\x2c\x73\xe1\x52\xf0\x50\x6a\x6a\xaa\x28\x35\x27\x30\x37\xd2\
\xf0\x52\xc3\x91\x9e\x9a\x8a\xba\x8e\x1d\x53\x5d\xb9\xb9\x35\xf3\
\x50\x5d\xea\xc8\xa9\xaa\x3d\x3b\x6e\x7c\xd3\xb3\x2d\xc8\x4a\xe6\
\x08\x72\x55\x7b\xfa\x3e\xab\xa0\x63\xdb\x48\xe6\xcc\xcc\x03\xb7\
\xf2\x75\xf3\xa6\xa6\x9e\x89\xcc\x4c\x10\x64\xe6\xc6\x6e\x34\xcc\
\x4b\xd5\x0b\x73\x8c\x48\x45\x10\x04\x84\x05\x52\x28\xfe\x86\x73\
\x23\x6d\x9b\x62\x91\x42\x21\x12\xbb\x67\xc3\xb5\xc8\x6c\x15\x9e\
\x2b\x9c\x69\xda\x17\x2b\x5c\xfa\x2e\x48\xec\x4a\x74\xd5\x4a\xcd\
\xc9\x32\xe3\x5c\xcf\x73\x75\x5d\x27\x72\x6d\xbb\x1e\xf9\x62\xe2\
\x7e\xe9\xea\xee\xe0\xdc\xb1\x17\x9e\xea\xb8\x15\x6c\xa8\xf8\xea\
\x54\x6a\xb6\x6e\x9e\x89\x55\x4d\x1d\xdb\xb2\xa5\x2e\x77\xa1\x6b\
\x2c\x15\x9b\x97\x9a\x13\x18\x0f\x86\xad\x44\x6c\xe2\x87\x73\x91\
\x5c\x90\xa8\x99\xa2\xe7\xe7\x60\x05\xee\x1f\x7e\x3a\xa8\x35\xc3\
\xf2\x11\x96\x56\xc6\x57\xfd\xc3\x7f\xff\x53\x7e\x03\x8d\x9d\x7c\
\x01\xba\x12\x40\xba\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\
\x82\
\x00\x00\x03\x95\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4\x6c\x3b\
\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
\x09\x70\x48\x59\x73\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\
\x9c\x18\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xd8\x06\x09\x16\x07\
\x34\xb6\xaf\x33\x78\x00\x00\x03\x27\x49\x44\x41\x54\x38\xcb\xed\
\x95\xcb\x6b\x5d\x55\x14\x87\xbf\xfd\x38\xe7\x3e\xf2\xba\x37\xaf\
\xa6\x5e\xd2\xa8\x4d\xa1\x03\x71\x62\x35\x90\xd6\x88\x8a\xa0\x28\
\x52\xd0\x2a\xe8\x5f\xd0\x0e\xfc\x07\x1c\x3b\x72\xa6\x62\x11\x54\
\x50\x1c\x28\x48\xd1\x42\x55\x0a\xa2\xb1\x26\xb5\xad\x15\x05\xc1\
\xb6\x31\x48\xd2\xab\x79\xf5\x36\x37\x8f\x73\xef\x39\xe7\xee\xb3\
\x97\x83\x34\x51\x5a\x93\x8e\x1c\x08\xae\xd1\xda\xaf\x8f\xdf\xfe\
\xad\xc5\xde\xf0\x7f\xfc\xdb\xa1\x36\x93\xdd\x6f\x94\x5e\xe9\x1f\
\xee\x3d\x86\x51\xa5\x5b\x36\x69\x50\xa2\x40\xa9\xbf\x72\x0d\x4a\
\x29\x5c\x92\xd5\x17\x2e\x2d\xbe\x39\xf7\x52\xfd\xe5\xbf\x9f\xb1\
\x9b\x49\xef\xde\x9e\xa3\x95\x7d\x95\xd2\x40\x7a\x07\x81\x0a\x36\
\x26\x35\x04\x26\x20\x0c\x72\x68\xad\xf1\xda\x23\xda\x63\xb5\x45\
\x99\x0d\x78\x55\xcf\x96\x44\xe4\xe8\x1c\xdb\x80\xb5\x51\xe5\xee\
\xb8\x97\x03\x6d\x23\x00\xe4\x6d\x9e\xbb\xda\x87\xb9\xbb\x38\x4c\
\xa7\xee\x04\x60\x55\x56\xb8\x9a\xcc\x70\x35\x9b\xc1\x69\x87\x51\
\x06\xf1\xc2\xe5\xdc\xe5\xf2\xcd\xb7\xd4\x9b\x89\x88\x10\xbb\x98\
\xf9\x78\x1e\x87\x63\xb4\xe7\x41\x0e\x75\x8e\x41\xa2\x98\x5e\x9e\
\x62\x7a\x6d\x9a\xc0\x87\x8c\x14\x47\xb9\x37\xb8\x8f\xb4\x95\x70\
\x5d\x6a\x38\xd5\xfa\x47\x8f\xb7\x14\x4b\x26\x2c\xa6\xf3\x54\x82\
\x41\x9e\xe9\x3b\x42\xc5\xee\xe1\x93\x5f\x4f\x70\xa1\x79\x16\xdf\
\x96\x61\x43\x4b\x39\xe9\xe6\x40\xc7\x08\xa3\xf9\x31\xd2\x56\xc2\
\x17\xe9\x49\xe2\x30\xc6\x67\xb2\x03\x58\x84\xda\x5a\x8d\x52\xb9\
\xc4\xfe\xfc\x3d\x7c\x7c\xe5\x43\x3e\x6b\x7e\x4a\x7b\x77\x3b\x8f\
\x94\x1f\x43\x1c\x7c\x1b\x7f\xcd\x5c\xb3\x8a\x33\x2d\xc6\xda\x1f\
\xe5\xe2\xc2\x39\x7e\xb1\x3f\x83\xdc\x0a\xde\xb2\xc2\x67\x42\x21\
\x28\x30\xd2\x73\x90\xd9\xb5\x19\x4e\xd4\x3e\x62\xad\x63\x05\xa7\
\x1d\x07\xdb\x1e\xe2\xfe\x70\x94\x28\x8a\xb8\xa6\x96\x38\x9d\x9c\
\x62\x95\x3a\xc3\xe1\x7e\x1a\x49\x84\x97\x9d\x14\xe3\xc9\x77\xe5\
\x18\x2a\xde\xc9\xd4\xc2\x15\xfe\xa0\x8a\xc5\x50\x90\x22\x1a\x8d\
\x56\x8a\xc8\xaf\x13\xab\x06\xb1\x34\xf9\x4d\xa6\xd9\x15\xf6\x23\
\xeb\x20\xde\x6f\x0f\xf6\xde\x63\x8c\xc1\xa0\xd1\x5a\x43\x1e\x32\
\xed\x68\x99\x04\xa5\x36\xda\xdd\x69\x47\x4b\xa7\x1b\xeb\x80\x88\
\x42\x79\x8d\xec\x64\x85\x64\x42\x4c\x4c\xd5\xcd\xb2\xb7\x6b\x1f\
\x7d\x85\x3e\xb4\xd5\x18\x6d\xc9\xf0\x88\x08\x5a\x6b\x8c\x31\xf4\
\x9b\x5d\x0c\x9a\x21\xe6\xe2\x2a\xad\x20\x21\x73\x7e\x07\xb0\x03\
\x87\x63\x62\xed\x0c\x7b\x8a\x7b\x38\xdc\xfd\x1c\xa1\xca\xd1\x30\
\x11\x3f\xa4\xdf\x71\xbe\x3e\x49\x1c\x34\xc9\xe9\x3c\x4f\x84\x4f\
\xd3\xed\x7b\x39\xb7\x3e\x09\xc5\x0d\x51\xdb\x5b\x21\x19\xc6\x18\
\x26\x9a\xe3\x4c\xa6\xdf\xf0\x7c\xdf\x8b\xe4\xa2\x90\xcf\xdd\x49\
\xde\x6b\xbc\x8d\xe4\x84\x81\xb6\x01\x9e\x0c\x0f\xf3\xb8\x7d\x8a\
\x89\x85\x71\x7e\x2c\x7e\x4f\x18\x86\x64\x59\x76\x7b\x8f\x63\xd5\
\xe4\xad\xd5\xd7\x50\x5d\x8a\x67\xdb\x5f\xe0\x90\x3c\xcc\xef\xcc\
\xa2\xd1\x0c\x9a\x21\x7a\x7d\x3f\x67\x96\xbe\xe2\x83\xf4\x5d\x6c\
\x45\xe3\x32\xb9\x4d\xf1\x5a\x82\x35\x86\x20\xb4\x5c\x63\x91\xd7\
\xa3\x57\xb9\x60\xcf\xf2\x80\x1d\x65\xc0\xec\x46\x3c\x4c\x25\x97\
\x78\x3f\x7a\x87\x9f\x72\x17\xd1\x15\x08\x74\x48\x96\x35\xf1\x6e\
\x07\x70\xda\x48\x97\xe3\xeb\x69\xd9\xf4\x5b\xb4\x28\x56\xa8\x73\
\x3a\x3b\xc5\x78\xf2\x25\x05\x29\x40\xa6\x48\x6c\x8c\x74\x08\x36\
\xb4\x98\x96\x21\xa5\x45\x6d\xa1\x46\xa3\x1e\x2f\x6f\x0b\x5e\x5f\
\x8a\x8e\xcf\x9e\xaf\x1e\x0b\x72\x41\x49\xdd\x28\xe9\x66\x9b\x6d\
\x3d\x9f\x37\x8d\x6f\x08\xaa\xaf\x2f\x45\xc7\xff\xfb\x3f\xc8\x9f\
\xfa\xf1\x66\x0f\xd0\x45\x3e\x19\x00\x00\x00\x00\x49\x45\x4e\x44\
\xae\x42\x60\x82\
\x00\x00\x03\x8e\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4\x6c\x3b\
\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\
\x09\x70\x48\x59\x73\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\
\x9c\x18\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xd8\x06\x09\x16\x09\
\x28\x3c\x2d\x42\xb9\x00\x00\x03\x20\x49\x44\x41\x54\x38\xcb\xed\
\x95\x5d\x6b\x5c\x45\x18\xc7\x7f\x33\x73\xce\xd9\x5d\x92\x4d\xcf\
\x66\xb3\x89\xc9\x26\xd8\x24\x48\x6f\x14\x4c\x43\xb7\x46\xe8\x85\
\xa5\x78\x63\xb5\xf8\x31\xda\xaf\xe0\x8d\x5e\xf8\x15\x2c\x88\x50\
\x7a\x25\xa2\xa8\x60\xbd\xd2\xd8\xde\xf4\xbd\xdd\x08\x4a\x2a\xac\
\x2c\xa1\x49\x76\x93\x34\x27\xbb\x9b\x75\x5f\xce\xd9\x33\x33\x5e\
\x6c\xd2\x8a\x64\xe3\x95\x17\x82\x03\x03\xcf\xc0\xcc\xef\x79\x9e\
\xff\xf3\x87\x81\xff\xd7\xbf\xbd\xc4\x61\xf0\xd1\x2b\xf3\x1f\xcf\
\x8d\x8f\x5f\x51\x52\xf8\x7f\xbf\x24\x01\x2b\x04\x42\x88\x17\x31\
\x02\x29\x20\xd4\xba\x5e\xaa\x56\x3f\xf9\xb0\x54\xfe\xe0\xaf\x6f\
\x9c\xc3\x60\x36\x97\xbb\x3c\x3f\x33\xe3\xdb\x5c\x0e\xe9\x3a\x07\
\x59\x05\xca\x75\xf1\x3c\x0f\x29\x25\xc2\x5a\xa4\x31\x48\xc7\x41\
\x1d\x24\x32\xd5\x8a\x6f\x8d\xbd\xcc\x20\xb0\x92\x22\x13\xfb\x3e\
\xa3\xaf\x2f\x00\xe0\x26\x12\x9c\x98\x9d\x65\xe4\xe4\x49\x9c\xa1\
\x61\x00\xf4\x1f\x4d\x5a\x1b\x9b\x84\x95\x4d\xa4\x8e\x11\x4a\xd1\
\xc1\xe2\x3d\xf9\x2d\x73\x54\x97\x00\x18\x0b\x71\xb7\x4b\x7b\x67\
\x07\x74\xcc\x64\xe1\x2c\xb9\xc2\x59\x22\x60\xb7\x5c\xa6\xfe\x74\
\x0d\xeb\xba\x64\x16\x17\x19\x7e\xed\x55\xa2\x30\x22\xae\xd5\x21\
\x8e\x8f\xd4\xd8\x79\x01\x36\x74\x9e\x3d\x23\x39\x35\x45\xfe\xe2\
\xbb\x24\xf3\x53\xac\x7e\x7f\x83\xfa\x4a\x91\x94\xb5\xb8\x8e\x4b\
\xd2\xf7\xc9\x2e\x2c\xe0\x9f\x29\xd0\x0b\x43\x1a\xcb\xcb\x88\x30\
\xc4\x58\x33\x18\x6c\xad\x65\x7f\x6f\x8f\x97\x46\x4e\x90\x3e\x75\
\x8a\x5f\xbe\xfd\x86\xe0\xc7\x1f\xc8\xa4\xd3\x4c\x9e\x3b\x47\x6c\
\xa1\x7e\xff\x1e\xc1\xf6\x16\x32\x8e\xf1\x97\xde\x64\x6f\xe5\x67\
\x28\x95\xb0\xd6\x32\x50\x0a\x6d\x2c\x5e\x2a\xc9\x64\xe1\x0c\x8d\
\x8d\x75\xd6\x6f\x7c\x47\xaa\xdd\x42\x68\xcd\x68\xe1\x0d\x46\x16\
\x4f\xd3\x6a\xb5\xd0\xb5\x1a\xb5\x5b\x37\x31\xfb\xfb\x0c\xcd\xcf\
\x13\xb6\x5b\x47\x82\x9f\x57\x8c\x35\xa4\x93\x29\xd2\xd3\x33\x6c\
\x95\xcb\xe8\xad\x2a\x3a\x91\xc0\xa4\x52\x20\x25\x02\x81\x6e\xb7\
\xb0\x51\x8f\x5e\xd8\x25\x5a\x7f\x4a\x6a\x34\x4b\x6c\xfb\x45\x0d\
\xd6\xd8\x18\x94\x52\x7d\x7f\x4a\x89\x27\x24\x32\x8e\x11\xbd\x1e\
\x42\xf4\xed\x2e\xb4\x46\xc4\x3d\x84\xea\x37\x6a\xa5\xe8\xef\x7f\
\x92\x82\xb0\x4b\xb7\x5a\x61\x74\x6e\x8e\xa1\xb1\x2c\x4a\x29\xa4\
\x72\xc0\x1a\xac\xb5\x48\x21\x51\x4a\xe1\x8d\x8d\x91\xc8\xe7\x69\
\x55\xaa\xa8\xa8\x87\x36\xfa\x18\x30\x16\xab\x35\xbb\x0f\x1f\x90\
\x9e\xca\x33\xfd\xce\x45\xa4\xe7\x21\x3a\x1d\x9a\xc5\x15\x76\x1e\
\x3d\x42\x45\x21\x2a\x91\xc0\x3f\x7f\x01\xe1\x67\x08\x8a\x8f\x49\
\x49\x71\xbc\x14\x56\x6b\x94\x52\xd4\xef\xdf\x63\xff\xe1\x03\x5e\
\xbe\xf4\x3e\x29\x2f\x41\xe3\xa7\x65\xb6\xbf\xfa\x02\x6d\x2d\xb9\
\x89\x09\xfc\x0b\x6f\x33\xf2\xd6\x79\x36\xee\xde\x45\xae\xfe\x8a\
\xe7\x79\x68\xad\x07\x83\xb5\xb1\x28\xa5\xb0\x61\xc8\xe6\xf5\x6b\
\x4c\x0b\xc1\xc4\x7b\x97\xc8\x2e\x2d\xd1\xab\x56\x11\x42\x90\xc8\
\xe7\x11\xa3\x59\x2a\x77\x6e\x13\x7c\xfd\x25\x39\xd7\xc3\xe8\x18\
\x63\x8e\xf1\x71\x7c\x30\x3c\xcf\x71\xd0\x41\x40\xe5\xb3\x4f\x19\
\x5e\x29\x32\xbc\x70\x1a\x2f\x37\x8e\x06\x76\x4b\xbf\x53\x7b\xfc\
\x39\xe6\xc9\x2a\x39\xa9\x50\x9e\x8b\xe9\xc4\x47\x6a\xfc\x1c\xdc\
\x8e\xa2\x5a\xbd\xdb\xcd\x8c\x39\x0e\x56\x08\x68\x34\xa8\xdd\xba\
\x49\xe3\xce\x6d\x48\x26\xd1\x08\x54\x14\xe2\x01\x49\xc7\x21\x56\
\x8a\xb8\x17\xb1\x1d\x04\xd4\x3b\xdd\xda\x40\x70\xd0\x6c\x5e\x2d\
\xae\xad\x5d\xf1\x5c\xcf\x3f\x9c\xe8\xa1\xcd\x18\x70\x3e\x28\xa8\
\x1e\x34\x9b\x57\xff\xfb\x3f\xc8\x9f\xa2\x63\x68\x95\x98\xd0\x55\
\x56\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x03\x11\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
\x00\x00\x00\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\
\xa7\x93\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\
\x0b\x12\x01\xd2\xdd\x7e\xfc\x00\x00\x00\x07\x74\x49\x4d\x45\x07\
\xd4\x0c\x0e\x14\x29\x37\x87\x80\x5f\xe3\x00\x00\x02\x9e\x49\x44\
\x41\x54\x78\xda\x95\x92\x5b\x48\x53\x01\x18\xc7\xff\x3b\x3b\xd3\
\xb9\xa6\x39\x2f\x9b\x97\xb4\x24\x13\xa7\xb9\x12\xb1\xde\x7a\xb1\
\x0c\xc4\x4c\x34\x08\xc5\x34\x8d\x0a\x0c\x34\x7b\x29\x84\x8c\x22\
\x33\xd0\x61\x3d\x16\x51\x12\x2a\x09\xf9\x50\xa1\xf8\x30\x12\xba\
\x4b\x37\x9b\x28\xa3\x79\x69\xa6\xa6\xe7\xec\xd2\xe6\xe6\x39\x67\
\x3b\x97\x5e\x5a\x99\x5b\x50\xdf\xdb\xf7\x7d\xfc\x7f\x1f\xfc\xbf\
\x3f\xf0\x1f\x15\x73\x1e\xd9\x9a\x2e\x3c\x24\x33\xb1\x3b\x38\x23\
\xfe\x45\x18\xdd\x82\x54\x4d\x27\x6e\xcb\xb5\x98\x10\x56\x50\xc2\
\x4f\x43\x0c\xee\xc8\x70\x82\x95\x95\x9e\x84\xd8\x58\xa9\x66\xca\
\x32\xb9\x43\x4e\xb2\xfc\x3b\xdb\x1c\xd5\xd4\x3f\x5c\x44\xe8\x24\
\x52\xa0\x41\x01\xb0\xff\xf5\x1a\xc3\xf4\x95\xf0\x82\xd1\xf1\x78\
\xa4\xdc\xab\x89\x53\xd6\xd4\x9d\xd4\x1f\x7d\x69\xad\x10\x53\x8c\
\xa4\xa4\x3e\x8e\x6f\x11\x7b\xf1\x02\x80\x3a\xac\x78\x75\xf5\x8e\
\x21\x20\x5c\x63\xe6\x1c\xc7\xa4\xba\x53\xd9\x23\x00\x54\x64\x06\
\x48\x7d\xa7\x7a\x5e\xd7\x46\x4a\xcd\x17\x0d\xd3\x91\x5a\x79\x01\
\x00\x79\x58\x0f\x94\xca\xef\xed\x94\xcf\xaa\xf4\xad\x05\x30\x6b\
\xf5\xbc\x01\xc0\xa8\x8e\xa0\x79\x59\xf4\xa6\x1d\x8a\xc8\x44\x7d\
\x7d\xf6\xf6\xc6\x86\xbc\xfd\xc0\x6f\x0f\x7e\x01\x86\x86\xce\xa8\
\x78\x19\x5d\xcc\x70\x7e\xf8\x39\x01\xd4\x0a\x63\x53\x37\x42\x4f\
\xc4\xe3\x6a\x16\x95\xb0\x76\xba\x72\x27\xd4\xd1\x0a\xa4\x67\xa8\
\xcb\x00\x44\x86\x00\x72\x73\xa5\x24\x2e\xe0\x89\x08\xf6\x7e\x41\
\x08\xc8\x93\xd0\x23\xd2\x60\x0f\xeb\xf4\xc3\xc9\xc9\x9b\x00\x00\
\x2a\x95\x3c\x05\x80\x2a\x04\x60\x36\x3b\xdd\x3c\x38\x09\x00\x08\
\x42\x86\x2d\x45\x9a\x73\x07\xb2\xf3\x0a\x8b\xb8\x9c\xc1\xda\xea\
\x82\x31\x99\x4c\x06\x00\xb0\xd3\x1c\x0b\x40\x0a\x01\x94\x95\x3d\
\x70\xd9\x5d\xac\x19\x00\xa2\x54\x24\x0e\x1a\xb6\xe6\x47\x8c\x8a\
\x96\xa6\xaa\x9c\xd2\xd8\x44\xf2\x0a\x2f\x8a\xe0\x38\x01\x1f\xde\
\xd2\x13\x00\x7c\xe1\x4c\x14\x5f\x3f\xa7\xba\x58\x86\x07\x41\xc8\
\x30\x69\x59\x72\xf6\xdf\x9a\xac\xcd\x48\x8f\xeb\x76\x31\x54\x94\
\x3f\x20\xe0\xd5\xb3\xe5\x35\xd3\xf0\xc2\x3d\x00\xfe\x10\x00\xb9\
\x0d\xc4\x59\xb3\x69\xa9\xf3\xd1\x47\x87\x9d\x66\x50\x55\x96\x45\
\x1a\x76\x25\xba\xb5\xf1\x9a\x48\x00\x98\x9a\x70\x06\x6e\x5c\x37\
\x1b\xdd\x6e\x6e\xb4\xa3\xa3\xea\xcf\x37\x46\x55\x42\xa1\x2c\x46\
\xbb\x40\xa3\x77\xf0\xd3\xe7\xb8\x13\x97\x9f\x7e\x99\x18\x77\xcc\
\xb4\xb6\xed\x19\x98\xb1\xb1\x0d\x82\x28\xc2\xeb\xe5\x7d\x4e\xbb\
\xd0\xc7\xb2\x77\x5b\xd7\x58\x7b\x43\xb8\x1c\x29\x00\x68\x55\x15\
\xb8\x1f\xb9\x0f\xdd\x3f\xd3\x96\xf6\xc4\x54\x7a\xc1\x4a\x55\x4b\
\x56\xaa\x5a\x72\xf9\x5a\xfc\xbd\x03\xe5\x76\x85\x82\x28\x0c\x8a\
\xe4\xeb\x3d\x00\xe0\x53\xe4\x63\x41\xa4\x01\x61\x11\x63\x00\x3c\
\x8b\x5f\x99\x71\x8f\xdb\x9f\x6a\x9b\x5d\x8d\x19\x1c\xb4\xcc\xdf\
\x34\xbe\xbf\xe4\x71\xfb\x4d\xeb\xc3\xb4\xb1\x08\xb9\x0e\x9b\x37\
\xcc\x48\x00\x1a\x00\x31\x00\x64\xeb\x17\x3f\x00\x3d\x4b\x18\xbb\
\x0e\x57\x7e\xbc\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\
\x00\x00\x13\x3e\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x20\x00\x00\x00\x20\x08\x06\x00\x00\x00\x73\x7a\x7a\xf4\
\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x13\x00\x00\x0b\x13\
\x01\x00\x9a\x9c\x18\x00\x00\x0a\x4f\x69\x43\x43\x50\x50\x68\x6f\
\x74\x6f\x73\x68\x6f\x70\x20\x49\x43\x43\x20\x70\x72\x6f\x66\x69\
\x6c\x65\x00\x00\x78\xda\x9d\x53\x67\x54\x53\xe9\x16\x3d\xf7\xde\
\xf4\x42\x4b\x88\x80\x94\x4b\x6f\x52\x15\x08\x20\x52\x42\x8b\x80\
\x14\x91\x26\x2a\x21\x09\x10\x4a\x88\x21\xa1\xd9\x15\x51\xc1\x11\
\x45\x45\x04\x1b\xc8\xa0\x88\x03\x8e\x8e\x80\x8c\x15\x51\x2c\x0c\
\x8a\x0a\xd8\x07\xe4\x21\xa2\x8e\x83\xa3\x88\x8a\xca\xfb\xe1\x7b\
\xa3\x6b\xd6\xbc\xf7\xe6\xcd\xfe\xb5\xd7\x3e\xe7\xac\xf3\x9d\xb3\
\xcf\x07\xc0\x08\x0c\x96\x48\x33\x51\x35\x80\x0c\xa9\x42\x1e\x11\
\xe0\x83\xc7\xc4\xc6\xe1\xe4\x2e\x40\x81\x0a\x24\x70\x00\x10\x08\
\xb3\x64\x21\x73\xfd\x23\x01\x00\xf8\x7e\x3c\x3c\x2b\x22\xc0\x07\
\xbe\x00\x01\x78\xd3\x0b\x08\x00\xc0\x4d\x9b\xc0\x30\x1c\x87\xff\
\x0f\xea\x42\x99\x5c\x01\x80\x84\x01\xc0\x74\x91\x38\x4b\x08\x80\
\x14\x00\x40\x7a\x8e\x42\xa6\x00\x40\x46\x01\x80\x9d\x98\x26\x53\
\x00\xa0\x04\x00\x60\xcb\x63\x62\xe3\x00\x50\x2d\x00\x60\x27\x7f\
\xe6\xd3\x00\x80\x9d\xf8\x99\x7b\x01\x00\x5b\x94\x21\x15\x01\xa0\
\x91\x00\x20\x13\x65\x88\x44\x00\x68\x3b\x00\xac\xcf\x56\x8a\x45\
\x00\x58\x30\x00\x14\x66\x4b\xc4\x39\x00\xd8\x2d\x00\x30\x49\x57\
\x66\x48\x00\xb0\xb7\x00\xc0\xce\x10\x0b\xb2\x00\x08\x0c\x00\x30\
\x51\x88\x85\x29\x00\x04\x7b\x00\x60\xc8\x23\x23\x78\x00\x84\x99\
\x00\x14\x46\xf2\x57\x3c\xf1\x2b\xae\x10\xe7\x2a\x00\x00\x78\x99\
\xb2\x3c\xb9\x24\x39\x45\x81\x5b\x08\x2d\x71\x07\x57\x57\x2e\x1e\
\x28\xce\x49\x17\x2b\x14\x36\x61\x02\x61\x9a\x40\x2e\xc2\x79\x99\
\x19\x32\x81\x34\x0f\xe0\xf3\xcc\x00\x00\xa0\x91\x15\x11\xe0\x83\
\xf3\xfd\x78\xce\x0e\xae\xce\xce\x36\x8e\xb6\x0e\x5f\x2d\xea\xbf\
\x06\xff\x22\x62\x62\xe3\xfe\xe5\xcf\xab\x70\x40\x00\x00\xe1\x74\
\x7e\xd1\xfe\x2c\x2f\xb3\x1a\x80\x3b\x06\x80\x6d\xfe\xa2\x25\xee\
\x04\x68\x5e\x0b\xa0\x75\xf7\x8b\x66\xb2\x0f\x40\xb5\x00\xa0\xe9\
\xda\x57\xf3\x70\xf8\x7e\x3c\x3c\x45\xa1\x90\xb9\xd9\xd9\xe5\xe4\
\xe4\xd8\x4a\xc4\x42\x5b\x61\xca\x57\x7d\xfe\x67\xc2\x5f\xc0\x57\
\xfd\x6c\xf9\x7e\x3c\xfc\xf7\xf5\xe0\xbe\xe2\x24\x81\x32\x5d\x81\
\x47\x04\xf8\xe0\xc2\xcc\xf4\x4c\xa5\x1c\xcf\x92\x09\x84\x62\xdc\
\xe6\x8f\x47\xfc\xb7\x0b\xff\xfc\x1d\xd3\x22\xc4\x49\x62\xb9\x58\
\x2a\x14\xe3\x51\x12\x71\x8e\x44\x9a\x8c\xf3\x32\xa5\x22\x89\x42\
\x92\x29\xc5\x25\xd2\xff\x64\xe2\xdf\x2c\xfb\x03\x3e\xdf\x35\x00\
\xb0\x6a\x3e\x01\x7b\x91\x2d\xa8\x5d\x63\x03\xf6\x4b\x27\x10\x58\
\x74\xc0\xe2\xf7\x00\x00\xf2\xbb\x6f\xc1\xd4\x28\x08\x03\x80\x68\
\x83\xe1\xcf\x77\xff\xef\x3f\xfd\x47\xa0\x25\x00\x80\x66\x49\x92\
\x71\x00\x00\x5e\x44\x24\x2e\x54\xca\xb3\x3f\xc7\x08\x00\x00\x44\
\xa0\x81\x2a\xb0\x41\x1b\xf4\xc1\x18\x2c\xc0\x06\x1c\xc1\x05\xdc\
\xc1\x0b\xfc\x60\x36\x84\x42\x24\xc4\xc2\x42\x10\x42\x0a\x64\x80\
\x1c\x72\x60\x29\xac\x82\x42\x28\x86\xcd\xb0\x1d\x2a\x60\x2f\xd4\
\x40\x1d\x34\xc0\x51\x68\x86\x93\x70\x0e\x2e\xc2\x55\xb8\x0e\x3d\
\x70\x0f\xfa\x61\x08\x9e\xc1\x28\xbc\x81\x09\x04\x41\xc8\x08\x13\
\x61\x21\xda\x88\x01\x62\x8a\x58\x23\x8e\x08\x17\x99\x85\xf8\x21\
\xc1\x48\x04\x12\x8b\x24\x20\xc9\x88\x14\x51\x22\x4b\x91\x35\x48\
\x31\x52\x8a\x54\x20\x55\x48\x1d\xf2\x3d\x72\x02\x39\x87\x5c\x46\
\xba\x91\x3b\xc8\x00\x32\x82\xfc\x86\xbc\x47\x31\x94\x81\xb2\x51\
\x3d\xd4\x0c\xb5\x43\xb9\xa8\x37\x1a\x84\x46\xa2\x0b\xd0\x64\x74\
\x31\x9a\x8f\x16\xa0\x9b\xd0\x72\xb4\x1a\x3d\x8c\x36\xa1\xe7\xd0\
\xab\x68\x0f\xda\x8f\x3e\x43\xc7\x30\xc0\xe8\x18\x07\x33\xc4\x6c\
\x30\x2e\xc6\xc3\x42\xb1\x38\x2c\x09\x93\x63\xcb\xb1\x22\xac\x0c\
\xab\xc6\x1a\xb0\x56\xac\x03\xbb\x89\xf5\x63\xcf\xb1\x77\x04\x12\
\x81\x45\xc0\x09\x36\x04\x77\x42\x20\x61\x1e\x41\x48\x58\x4c\x58\
\x4e\xd8\x48\xa8\x20\x1c\x24\x34\x11\xda\x09\x37\x09\x03\x84\x51\
\xc2\x27\x22\x93\xa8\x4b\xb4\x26\xba\x11\xf9\xc4\x18\x62\x32\x31\
\x87\x58\x48\x2c\x23\xd6\x12\x8f\x13\x2f\x10\x7b\x88\x43\xc4\x37\
\x24\x12\x89\x43\x32\x27\xb9\x90\x02\x49\xb1\xa4\x54\xd2\x12\xd2\
\x46\xd2\x6e\x52\x23\xe9\x2c\xa9\x9b\x34\x48\x1a\x23\x93\xc9\xda\
\x64\x6b\xb2\x07\x39\x94\x2c\x20\x2b\xc8\x85\xe4\x9d\xe4\xc3\xe4\
\x33\xe4\x1b\xe4\x21\xf2\x5b\x0a\x9d\x62\x40\x71\xa4\xf8\x53\xe2\
\x28\x52\xca\x6a\x4a\x19\xe5\x10\xe5\x34\xe5\x06\x65\x98\x32\x41\
\x55\xa3\x9a\x52\xdd\xa8\xa1\x54\x11\x35\x8f\x5a\x42\xad\xa1\xb6\
\x52\xaf\x51\x87\xa8\x13\x34\x75\x9a\x39\xcd\x83\x16\x49\x4b\xa5\
\xad\xa2\x95\xd3\x1a\x68\x17\x68\xf7\x69\xaf\xe8\x74\xba\x11\xdd\
\x95\x1e\x4e\x97\xd0\x57\xd2\xcb\xe9\x47\xe8\x97\xe8\x03\xf4\x77\
\x0c\x0d\x86\x15\x83\xc7\x88\x67\x28\x19\x9b\x18\x07\x18\x67\x19\
\x77\x18\xaf\x98\x4c\xa6\x19\xd3\x8b\x19\xc7\x54\x30\x37\x31\xeb\
\x98\xe7\x99\x0f\x99\x6f\x55\x58\x2a\xb6\x2a\x7c\x15\x91\xca\x0a\
\x95\x4a\x95\x26\x95\x1b\x2a\x2f\x54\xa9\xaa\xa6\xaa\xde\xaa\x0b\
\x55\xf3\x55\xcb\x54\x8f\xa9\x5e\x53\x7d\xae\x46\x55\x33\x53\xe3\
\xa9\x09\xd4\x96\xab\x55\xaa\x9d\x50\xeb\x53\x1b\x53\x67\xa9\x3b\
\xa8\x87\xaa\x67\xa8\x6f\x54\x3f\xa4\x7e\x59\xfd\x89\x06\x59\xc3\
\x4c\xc3\x4f\x43\xa4\x51\xa0\xb1\x5f\xe3\xbc\xc6\x20\x0b\x63\x19\
\xb3\x78\x2c\x21\x6b\x0d\xab\x86\x75\x81\x35\xc4\x26\xb1\xcd\xd9\
\x7c\x76\x2a\xbb\x98\xfd\x1d\xbb\x8b\x3d\xaa\xa9\xa1\x39\x43\x33\
\x4a\x33\x57\xb3\x52\xf3\x94\x66\x3f\x07\xe3\x98\x71\xf8\x9c\x74\
\x4e\x09\xe7\x28\xa7\x97\xf3\x7e\x8a\xde\x14\xef\x29\xe2\x29\x1b\
\xa6\x34\x4c\xb9\x31\x65\x5c\x6b\xaa\x96\x97\x96\x58\xab\x48\xab\
\x51\xab\x47\xeb\xbd\x36\xae\xed\xa7\x9d\xa6\xbd\x45\xbb\x59\xfb\
\x81\x0e\x41\xc7\x4a\x27\x5c\x27\x47\x67\x8f\xce\x05\x9d\xe7\x53\
\xd9\x53\xdd\xa7\x0a\xa7\x16\x4d\x3d\x3a\xf5\xae\x2e\xaa\x6b\xa5\
\x1b\xa1\xbb\x44\x77\xbf\x6e\xa7\xee\x98\x9e\xbe\x5e\x80\x9e\x4c\
\x6f\xa7\xde\x79\xbd\xe7\xfa\x1c\x7d\x2f\xfd\x54\xfd\x6d\xfa\xa7\
\xf5\x47\x0c\x58\x06\xb3\x0c\x24\x06\xdb\x0c\xce\x18\x3c\xc5\x35\
\x71\x6f\x3c\x1d\x2f\xc7\xdb\xf1\x51\x43\x5d\xc3\x40\x43\xa5\x61\
\x95\x61\x97\xe1\x84\x91\xb9\xd1\x3c\xa3\xd5\x46\x8d\x46\x0f\x8c\
\x69\xc6\x5c\xe3\x24\xe3\x6d\xc6\x6d\xc6\xa3\x26\x06\x26\x21\x26\
\x4b\x4d\xea\x4d\xee\x9a\x52\x4d\xb9\xa6\x29\xa6\x3b\x4c\x3b\x4c\
\xc7\xcd\xcc\xcd\xa2\xcd\xd6\x99\x35\x9b\x3d\x31\xd7\x32\xe7\x9b\
\xe7\x9b\xd7\x9b\xdf\xb7\x60\x5a\x78\x5a\x2c\xb6\xa8\xb6\xb8\x65\
\x49\xb2\xe4\x5a\xa6\x59\xee\xb6\xbc\x6e\x85\x5a\x39\x59\xa5\x58\
\x55\x5a\x5d\xb3\x46\xad\x9d\xad\x25\xd6\xbb\xad\xbb\xa7\x11\xa7\
\xb9\x4e\x93\x4e\xab\x9e\xd6\x67\xc3\xb0\xf1\xb6\xc9\xb6\xa9\xb7\
\x19\xb0\xe5\xd8\x06\xdb\xae\xb6\x6d\xb6\x7d\x61\x67\x62\x17\x67\
\xb7\xc5\xae\xc3\xee\x93\xbd\x93\x7d\xba\x7d\x8d\xfd\x3d\x07\x0d\
\x87\xd9\x0e\xab\x1d\x5a\x1d\x7e\x73\xb4\x72\x14\x3a\x56\x3a\xde\
\x9a\xce\x9c\xee\x3f\x7d\xc5\xf4\x96\xe9\x2f\x67\x58\xcf\x10\xcf\
\xd8\x33\xe3\xb6\x13\xcb\x29\xc4\x69\x9d\x53\x9b\xd3\x47\x67\x17\
\x67\xb9\x73\x83\xf3\x88\x8b\x89\x4b\x82\xcb\x2e\x97\x3e\x2e\x9b\
\x1b\xc6\xdd\xc8\xbd\xe4\x4a\x74\xf5\x71\x5d\xe1\x7a\xd2\xf5\x9d\
\x9b\xb3\x9b\xc2\xed\xa8\xdb\xaf\xee\x36\xee\x69\xee\x87\xdc\x9f\
\xcc\x34\x9f\x29\x9e\x59\x33\x73\xd0\xc3\xc8\x43\xe0\x51\xe5\xd1\
\x3f\x0b\x9f\x95\x30\x6b\xdf\xac\x7e\x4f\x43\x4f\x81\x67\xb5\xe7\
\x23\x2f\x63\x2f\x91\x57\xad\xd7\xb0\xb7\xa5\x77\xaa\xf7\x61\xef\
\x17\x3e\xf6\x3e\x72\x9f\xe3\x3e\xe3\x3c\x37\xde\x32\xde\x59\x5f\
\xcc\x37\xc0\xb7\xc8\xb7\xcb\x4f\xc3\x6f\x9e\x5f\x85\xdf\x43\x7f\
\x23\xff\x64\xff\x7a\xff\xd1\x00\xa7\x80\x25\x01\x67\x03\x89\x81\
\x41\x81\x5b\x02\xfb\xf8\x7a\x7c\x21\xbf\x8e\x3f\x3a\xdb\x65\xf6\
\xb2\xd9\xed\x41\x8c\xa0\xb9\x41\x15\x41\x8f\x82\xad\x82\xe5\xc1\
\xad\x21\x68\xc8\xec\x90\xad\x21\xf7\xe7\x98\xce\x91\xce\x69\x0e\
\x85\x50\x7e\xe8\xd6\xd0\x07\x61\xe6\x61\x8b\xc3\x7e\x0c\x27\x85\
\x87\x85\x57\x86\x3f\x8e\x70\x88\x58\x1a\xd1\x31\x97\x35\x77\xd1\
\xdc\x43\x73\xdf\x44\xfa\x44\x96\x44\xde\x9b\x67\x31\x4f\x39\xaf\
\x2d\x4a\x35\x2a\x3e\xaa\x2e\x6a\x3c\xda\x37\xba\x34\xba\x3f\xc6\
\x2e\x66\x59\xcc\xd5\x58\x9d\x58\x49\x6c\x4b\x1c\x39\x2e\x2a\xae\
\x36\x6e\x6c\xbe\xdf\xfc\xed\xf3\x87\xe2\x9d\xe2\x0b\xe3\x7b\x17\
\x98\x2f\xc8\x5d\x70\x79\xa1\xce\xc2\xf4\x85\xa7\x16\xa9\x2e\x12\
\x2c\x3a\x96\x40\x4c\x88\x4e\x38\x94\xf0\x41\x10\x2a\xa8\x16\x8c\
\x25\xf2\x13\x77\x25\x8e\x0a\x79\xc2\x1d\xc2\x67\x22\x2f\xd1\x36\
\xd1\x88\xd8\x43\x5c\x2a\x1e\x4e\xf2\x48\x2a\x4d\x7a\x92\xec\x91\
\xbc\x35\x79\x24\xc5\x33\xa5\x2c\xe5\xb9\x84\x27\xa9\x90\xbc\x4c\
\x0d\x4c\xdd\x9b\x3a\x9e\x16\x9a\x76\x20\x6d\x32\x3d\x3a\xbd\x31\
\x83\x92\x91\x90\x71\x42\xaa\x21\x4d\x93\xb6\x67\xea\x67\xe6\x66\
\x76\xcb\xac\x65\x85\xb2\xfe\xc5\x6e\x8b\xb7\x2f\x1e\x95\x07\xc9\
\x6b\xb3\x90\xac\x05\x59\x2d\x0a\xb6\x42\xa6\xe8\x54\x5a\x28\xd7\
\x2a\x07\xb2\x67\x65\x57\x66\xbf\xcd\x89\xca\x39\x96\xab\x9e\x2b\
\xcd\xed\xcc\xb3\xca\xdb\x90\x37\x9c\xef\x9f\xff\xed\x12\xc2\x12\
\xe1\x92\xb6\xa5\x86\x4b\x57\x2d\x1d\x58\xe6\xbd\xac\x6a\x39\xb2\
\x3c\x71\x79\xdb\x0a\xe3\x15\x05\x2b\x86\x56\x06\xac\x3c\xb8\x8a\
\xb6\x2a\x6d\xd5\x4f\xab\xed\x57\x97\xae\x7e\xbd\x26\x7a\x4d\x6b\
\x81\x5e\xc1\xca\x82\xc1\xb5\x01\x6b\xeb\x0b\x55\x0a\xe5\x85\x7d\
\xeb\xdc\xd7\xed\x5d\x4f\x58\x2f\x59\xdf\xb5\x61\xfa\x86\x9d\x1b\
\x3e\x15\x89\x8a\xae\x14\xdb\x17\x97\x15\x7f\xd8\x28\xdc\x78\xe5\
\x1b\x87\x6f\xca\xbf\x99\xdc\x94\xb4\xa9\xab\xc4\xb9\x64\xcf\x66\
\xd2\x66\xe9\xe6\xde\x2d\x9e\x5b\x0e\x96\xaa\x97\xe6\x97\x0e\x6e\
\x0d\xd9\xda\xb4\x0d\xdf\x56\xb4\xed\xf5\xf6\x45\xdb\x2f\x97\xcd\
\x28\xdb\xbb\x83\xb6\x43\xb9\xa3\xbf\x3c\xb8\xbc\x65\xa7\xc9\xce\
\xcd\x3b\x3f\x54\xa4\x54\xf4\x54\xfa\x54\x36\xee\xd2\xdd\xb5\x61\
\xd7\xf8\x6e\xd1\xee\x1b\x7b\xbc\xf6\x34\xec\xd5\xdb\x5b\xbc\xf7\
\xfd\x3e\xc9\xbe\xdb\x55\x01\x55\x4d\xd5\x66\xd5\x65\xfb\x49\xfb\
\xb3\xf7\x3f\xae\x89\xaa\xe9\xf8\x96\xfb\x6d\x5d\xad\x4e\x6d\x71\
\xed\xc7\x03\xd2\x03\xfd\x07\x23\x0e\xb6\xd7\xb9\xd4\xd5\x1d\xd2\
\x3d\x54\x52\x8f\xd6\x2b\xeb\x47\x0e\xc7\x1f\xbe\xfe\x9d\xef\x77\
\x2d\x0d\x36\x0d\x55\x8d\x9c\xc6\xe2\x23\x70\x44\x79\xe4\xe9\xf7\
\x09\xdf\xf7\x1e\x0d\x3a\xda\x76\x8c\x7b\xac\xe1\x07\xd3\x1f\x76\
\x1d\x67\x1d\x2f\x6a\x42\x9a\xf2\x9a\x46\x9b\x53\x9a\xfb\x5b\x62\
\x5b\xba\x4f\xcc\x3e\xd1\xd6\xea\xde\x7a\xfc\x47\xdb\x1f\x0f\x9c\
\x34\x3c\x59\x79\x4a\xf3\x54\xc9\x69\xda\xe9\x82\xd3\x93\x67\xf2\
\xcf\x8c\x9d\x95\x9d\x7d\x7e\x2e\xf9\xdc\x60\xdb\xa2\xb6\x7b\xe7\
\x63\xce\xdf\x6a\x0f\x6f\xef\xba\x10\x74\xe1\xd2\x45\xff\x8b\xe7\
\x3b\xbc\x3b\xce\x5c\xf2\xb8\x74\xf2\xb2\xdb\xe5\x13\x57\xb8\x57\
\x9a\xaf\x3a\x5f\x6d\xea\x74\xea\x3c\xfe\x93\xd3\x4f\xc7\xbb\x9c\
\xbb\x9a\xae\xb9\x5c\x6b\xb9\xee\x7a\xbd\xb5\x7b\x66\xf7\xe9\x1b\
\x9e\x37\xce\xdd\xf4\xbd\x79\xf1\x16\xff\xd6\xd5\x9e\x39\x3d\xdd\
\xbd\xf3\x7a\x6f\xf7\xc5\xf7\xf5\xdf\x16\xdd\x7e\x72\x27\xfd\xce\
\xcb\xbb\xd9\x77\x27\xee\xad\xbc\x4f\xbc\x5f\xf4\x40\xed\x41\xd9\
\x43\xdd\x87\xd5\x3f\x5b\xfe\xdc\xd8\xef\xdc\x7f\x6a\xc0\x77\xa0\
\xf3\xd1\xdc\x47\xf7\x06\x85\x83\xcf\xfe\x91\xf5\x8f\x0f\x43\x05\
\x8f\x99\x8f\xcb\x86\x0d\x86\xeb\x9e\x38\x3e\x39\x39\xe2\x3f\x72\
\xfd\xe9\xfc\xa7\x43\xcf\x64\xcf\x26\x9e\x17\xfe\xa2\xfe\xcb\xae\
\x17\x16\x2f\x7e\xf8\xd5\xeb\xd7\xce\xd1\x98\xd1\xa1\x97\xf2\x97\
\x93\xbf\x6d\x7c\xa5\xfd\xea\xc0\xeb\x19\xaf\xdb\xc6\xc2\xc6\x1e\
\xbe\xc9\x78\x33\x31\x5e\xf4\x56\xfb\xed\xc1\x77\xdc\x77\x1d\xef\
\xa3\xdf\x0f\x4f\xe4\x7c\x20\x7f\x28\xff\x68\xf9\xb1\xf5\x53\xd0\
\xa7\xfb\x93\x19\x93\x93\xff\x04\x03\x98\xf3\xfc\x63\x33\x2d\xdb\
\x00\x00\x00\x04\x67\x41\x4d\x41\x00\x00\xb1\x8e\x7c\xfb\x51\x93\
\x00\x00\x00\x20\x63\x48\x52\x4d\x00\x00\x7a\x25\x00\x00\x80\x83\
\x00\x00\xf9\xff\x00\x00\x80\xe9\x00\x00\x75\x30\x00\x00\xea\x60\
\x00\x00\x3a\x98\x00\x00\x17\x6f\x92\x5f\xc5\x46\x00\x00\x08\x59\
\x49\x44\x41\x54\x78\xda\x94\x96\x6b\x8c\x5d\x55\x15\xc7\xff\x6b\
\xef\x7d\xce\x7d\xcc\xb3\x33\x6d\xa7\xcc\x14\xda\x02\xa6\x29\x05\
\x94\x47\xc0\x58\x21\x3e\x0a\x58\x8d\x31\xe0\x23\x01\x0b\xa2\x41\
\x93\x0a\x24\x7c\x30\xd1\x26\x12\x3f\xa0\x51\x1a\x0d\x69\x42\x24\
\xa4\x31\xea\x07\x0d\x11\xf0\x85\xb1\x15\x1a\x11\x4a\x10\x11\x0a\
\x6d\x41\xa6\x33\x8c\x2d\xd3\x17\x6d\xe7\xce\xdc\xd7\xb9\xf7\x9c\
\xb3\xf7\x5e\xcb\x0f\xe7\xce\xbd\x73\x3b\x6d\xd5\x7d\xb3\x32\x37\
\x37\x27\xf7\xff\x5b\xff\xfd\x5f\xeb\x0e\xe1\x2c\x67\xed\xda\xb5\
\xd7\x6f\xd9\xb2\xe5\x9b\xd6\x5a\xcf\xcc\x22\x22\x60\x66\x88\x48\
\xfb\x19\x22\x6a\xff\x15\x11\x28\xa5\xc2\xa9\xa9\xa9\xf1\x1d\x3b\
\x76\xfc\x60\xfe\x19\xa5\x34\x0a\x85\x1c\xea\xf5\x08\xe7\x3a\x04\
\x00\x03\x03\x3d\xa3\x77\xdf\x75\xfd\x5d\x7f\xde\xb9\xff\xe9\xc9\
\x77\x67\x26\x37\x6e\xdc\xf8\x8d\x5d\xbb\x76\x3d\xde\x68\x34\x90\
\xa6\x29\xbc\xf7\xed\x9a\x87\x50\x4a\xb5\xcb\x7b\x0f\xe7\x1c\xf6\
\xec\xd9\xb3\x77\xf3\xe6\xcd\xd7\x02\xa0\xdb\x6e\xbd\x66\xb3\xd6\
\x1c\xfd\xee\xf7\x07\x9e\xb6\xd6\x9e\x13\xc0\x00\xc0\xc8\xc8\x92\
\x2b\x1e\xf9\xc9\x75\x3f\x9c\x7e\xef\xe0\xe1\xc9\x77\x31\xe9\x9c\
\xa3\x4a\xa5\x8a\x28\xaa\xc3\x5a\x0b\xef\x3d\x98\xb9\xed\x42\xab\
\x63\x10\x51\x17\x40\x14\x45\x1e\x80\x00\xe8\xbf\xff\xbe\xeb\xbf\
\x05\x7f\xf8\xc4\x93\x4f\xbd\xf9\x34\xce\x73\x0c\x00\xb0\xf7\x36\
\x8d\x66\xe0\x5d\xec\x00\x40\x81\xe3\x1c\x59\x58\x72\x80\xa4\x50\
\xe2\xe1\x39\x13\x11\x11\x08\x00\xf2\x1d\x17\xc4\x7b\x28\xe7\xa0\
\x7c\xc2\xad\xef\x4d\x7d\x5c\x91\x4a\xf9\xa4\xcb\x78\xce\x0b\x40\
\x83\x03\x57\x7c\xf9\xce\x47\x5f\xbc\x06\xa5\xb1\xb1\xaf\x2d\xb9\
\x21\xfa\x70\x6d\xf5\xca\x0f\xfe\x78\x77\x79\x41\xf7\x59\xd7\xcc\
\x59\x7f\x2d\x04\x10\x65\x1f\x88\x30\x98\x09\xa7\x4a\x6b\x56\x8f\
\xde\xbc\x75\xbb\x73\x1c\x3e\x39\x71\xe9\x68\xda\xbc\x72\x79\xb8\
\x8c\x6e\x00\xb0\xe7\x3c\x19\x08\x2e\xf9\xf8\x83\xcf\xbe\x58\xed\
\x5d\x35\x5a\x6b\x26\x30\x81\x82\xb5\x16\x51\xd4\xc8\x82\x46\xad\
\xa0\x74\x22\x73\xce\x6f\x32\x5a\xa3\x50\x28\x80\x88\x50\xaf\xd4\
\x40\x36\x41\x65\xf7\xa3\x5b\xe7\xf6\xff\xfa\x47\xe7\x74\x80\x00\
\x1d\xc5\x0e\x35\xe3\x51\x6e\x38\x18\x24\x59\x9b\x44\x99\x79\xb2\
\xd0\xc4\x6e\x3b\xb5\xc4\x58\x93\xfc\x0c\x79\xaa\x42\xeb\x02\x02\
\x13\x42\x8b\x01\xa0\x90\x72\x02\xc7\x31\xcc\x75\x07\xbf\xfe\xf9\
\x7b\xd7\x5e\xad\x48\x6d\x51\x4a\x97\xce\x04\xd0\x00\x07\x23\x4b\
\x07\xaf\xf8\xd2\xc7\xe8\xb2\x53\xfb\x5e\xd8\x57\xaa\xf5\xf5\xb2\
\xf3\x21\x37\x22\x70\xb3\xd1\xa9\xc6\xe2\xba\x44\x3d\x87\xf5\xfd\
\xff\xc2\x48\xaf\x60\xe5\xa0\xc6\xaa\xa1\x1c\x56\x0f\x17\xb0\x72\
\x40\x63\x79\xd1\x62\x38\x1f\xa3\xa7\x18\x2e\xc9\x99\xfc\x7a\x52\
\xa4\x53\x1b\x3f\x9b\x5d\x60\xe7\x65\x00\x54\xef\xdc\x30\x4d\xf7\
\x7d\x6a\x0e\x4b\x8f\xbf\xa4\x1f\x7a\xe5\xa2\x0a\x17\x47\x7a\x45\
\xc9\x82\x8e\xe5\xac\x59\xba\xff\x0b\x9b\xb0\xe1\xf2\xdb\xdb\xe3\
\x29\xe0\x2c\x0f\xad\xd0\x32\x5b\x78\x4e\x21\xe4\x30\x39\x3e\xfd\
\xd1\x43\x87\x0e\x43\x6b\xbd\x68\x0a\x54\xcf\x40\xdf\x60\x2a\x80\
\x0a\x7d\x80\x53\x47\xa7\x7b\xfb\x86\xc7\xa2\x62\x5f\x4b\x78\x5e\
\x5c\xce\xc8\x81\x00\x3a\x07\xa7\x2a\x60\xca\x9e\x13\x78\xb0\xf8\
\x16\x80\x05\x8b\x85\xe7\x04\x1e\x09\x04\xec\xfa\xf3\x2b\xa0\x34\
\x2d\x1e\x43\x61\x11\x52\x0a\x3a\x08\xb4\x1a\x5a\xb1\xd4\xe6\x8b\
\x50\xa4\x01\x9b\x74\xf4\x88\x16\xe5\xa0\x16\x45\x48\xac\x05\x8b\
\x6f\x75\xce\x10\xf1\x99\xb0\x38\x78\x4e\x5b\x00\x29\xaa\xb5\x8a\
\x2d\xcd\x35\xa0\xcd\x62\x00\xca\xe5\x03\x5d\xe8\x57\xe8\x29\x08\
\x90\xc4\xf5\x00\x04\xaf\x0d\x48\x13\x48\x65\x63\x20\x36\xcd\xdc\
\x58\x10\xc8\x6a\x9c\x22\xf5\x4d\x30\x3b\x88\x78\x78\xf1\x10\x71\
\xf0\xe2\x32\xfb\x5b\x0e\x38\x49\x51\xad\x57\xa3\x5a\x3d\x3a\x2b\
\x00\xef\xdb\x77\x74\xdf\xce\x67\x8a\x7d\xaf\xbf\x61\x0e\x99\x20\
\x5c\xa7\x54\x00\xa3\x35\x44\xb8\xd5\xb9\x00\xa2\x16\xe5\xa0\x16\
\x3b\x24\xb6\x06\x16\x0b\x16\x06\x8b\x6b\x97\x67\x0b\x2f\x29\x3c\
\xa7\x70\x3e\x41\xb5\x52\x2d\x47\x71\x03\xfa\x2c\x57\x90\x3c\xb2\
\x7d\xf7\xd6\x47\xb6\xc3\x99\x70\x60\xdd\xa5\xb7\xf7\xfe\xc9\x87\
\x06\xda\x28\xb0\x57\x9d\x31\x2f\xe6\x16\xed\x81\x84\x9b\x88\x6d\
\x15\x8c\x79\x07\x5c\xe6\x00\x77\xae\x80\x25\x41\x62\x63\x04\x26\
\xac\x2d\x1b\x1a\x05\x29\x59\x04\xe0\x5a\x05\x66\xeb\xb9\x32\x37\
\x13\xf6\x5f\x78\x51\x92\xcf\x65\x5d\x03\x10\x11\x10\x51\xfb\x17\
\x70\xfe\x34\x9b\x11\x52\x1f\xc1\x4b\x92\x85\x8f\x5b\xdd\x8b\xcd\
\x20\x38\x05\xc3\xc2\xba\x04\xa5\x39\x6f\x1b\xe5\x59\x28\xdd\x89\
\x32\xc3\x65\x21\x6c\x2f\x05\x1d\x84\xe1\xd2\xe5\x23\xbe\x90\x83\
\xd1\x04\xcb\xd4\xda\x49\x04\x78\x5e\xb4\x88\x9a\xa9\x43\x6c\x6b\
\xf0\x88\x21\xec\xb2\xf4\xcf\x8b\x8b\x03\xb7\x01\x3c\x6a\xf5\xd8\
\x55\x2b\xdc\x02\x50\xf0\x54\x87\xa3\xd9\x6e\x00\xf6\xce\xfa\xb9\
\xb9\x59\x5d\x1c\x1b\x8b\xc3\x10\x4a\xe9\x4e\xf0\x94\x5a\xb4\x07\
\xa2\x54\x10\x27\x75\xb0\x6e\x80\xb9\x13\xbe\x79\x17\x98\x1d\x84\
\x3c\x9c\x13\x24\x89\x8d\x9d\x15\x28\x26\x88\x69\x40\x4c\x15\x04\
\xea\x06\x20\xa5\xb5\x14\x8b\xc5\x9a\x08\x92\xc4\xa3\x3f\xa4\xf3\
\x6d\x7f\x34\x52\x8d\x38\xad\x43\x82\x7a\x6b\xf1\xb8\x56\x20\x5d\
\x2b\x0f\x1e\xa4\x08\xd6\x02\x69\x62\xeb\xce\x03\x3a\x48\x40\x41\
\xd4\xce\x53\x17\x80\x40\x10\xc7\x4e\xd8\x4b\x36\x7a\x9a\x20\x72\
\x6e\x84\x58\x4c\x96\x01\xaa\xc0\xf3\xc2\xe5\xe3\x00\x08\x08\x0a\
\x9a\x34\xac\x55\xb0\x29\x9f\xa6\x30\x01\xe5\x9a\x5d\x61\xee\x02\
\x00\x33\x23\x6d\xc4\x46\x18\xa9\x07\x6a\xcd\xee\x3b\xef\xe5\xc3\
\xc8\xcb\x0c\x04\x0a\x1e\x01\x1c\x4a\x48\x5c\x1d\x29\x97\xe0\xbc\
\x6d\xd9\x6e\xc1\x60\x28\x68\x28\x32\x30\x30\x48\xd2\x00\x64\xf8\
\x32\x13\xd8\x9b\x45\xa8\x28\x59\x57\x29\x11\x3d\xdf\x7d\x05\xda\
\x68\xea\x1b\x1a\x4c\x75\xf6\xb1\x70\x07\xa0\x47\x8e\xe3\xb2\xe6\
\xc3\xd0\x1c\x21\x9f\x2b\xa2\x98\xef\xc3\x50\xfe\x02\x24\x69\x0c\
\x1f\x36\xe1\x99\x5b\xb6\x33\x14\xe9\xae\x62\x06\x8a\x85\xde\x07\
\x44\xbb\x07\xa2\x46\x0d\xd6\x26\x50\x0a\xd0\x46\x6d\xed\x0e\xa1\
\x4b\x2c\x97\xa6\x4f\xe4\xfb\x46\x56\xd6\x25\x6c\xaf\xdf\x1e\x2a\
\x61\x75\xe1\x08\x3e\x79\xf5\x06\x04\x79\x01\x7b\x81\x22\x05\x65\
\x14\x52\x7d\x0c\x9e\x1d\x58\xb2\x29\xe9\x08\x1b\x28\x32\x20\x18\
\x14\x7a\x14\xd6\x5e\x39\x26\x83\xbd\x17\x90\xf7\x0e\xda\x10\xe6\
\xe6\xaa\xb0\x51\x6e\x5d\x17\x80\xd2\x61\x40\x43\x17\x8c\x24\x26\
\x5c\xb0\xfb\x81\x48\x86\xf1\x76\x73\x18\xc5\x83\x25\x7c\xe6\x13\
\xaf\xa2\xd0\x9f\x20\x89\x53\x24\xdc\x80\x75\x09\x3c\x33\x04\x0c\
\x05\xb5\x40\x5c\x43\xa9\x0c\x20\x5f\x08\xd0\xb7\xae\x44\x46\xd5\
\x11\xe6\x02\xc4\x15\x85\xf7\xf7\xfb\x27\xae\x5a\xbb\xf1\x1e\xd5\
\x1d\x01\xe7\xa8\x51\x8b\x72\x64\x40\x26\x0f\x0a\x5a\x65\x42\x40\
\x80\x57\xa3\x4f\xe3\x89\x3f\xae\xc7\xe9\x13\x35\x38\xd4\x61\x6d\
\xdc\x0e\x5c\x26\x9e\x75\xad\x94\x81\x52\x01\x34\x99\x76\x81\x09\
\xa4\x18\x95\x19\x8b\xbf\x3f\x53\xff\x4d\x34\xab\xbf\x02\xc5\xb6\
\xdb\x01\xa5\x11\xd5\x4b\x47\xe3\x89\x3d\xb3\x4a\xbc\xcf\x46\xc1\
\x33\xe5\x06\x96\x05\x63\x97\xae\x27\x66\x8c\xdb\x1b\xd1\x7c\xaa\
\x86\x5b\x36\xbd\x84\x25\xa3\x1e\x2e\xe1\xec\x3a\xe6\xc5\x5b\xa5\
\xdb\xef\x03\x28\x32\x08\xc2\x00\xd1\xac\xc2\x1b\x7f\xb1\xbf\xac\
\x9c\xb6\xf7\x0c\x0d\xc3\x41\xa4\x6b\xcc\x09\x40\x1e\x80\xea\x9a\
\x4c\x00\xc1\x8a\x0f\xdd\x31\xbc\x65\xdb\x0e\x93\xa6\x90\x52\x84\
\xca\xd1\x0a\x56\xca\x0b\xb8\xf5\x8e\x7f\x60\xd9\x2a\x0d\x4e\x75\
\xa7\xf3\x79\x00\x15\xb4\x41\xc2\x5c\x80\xea\x29\xc2\xfe\xe7\xf8\
\xf1\xda\x9c\xdb\x02\xed\x64\x68\xc9\x52\xdc\xb8\x61\x23\xf4\x19\
\xa3\xed\x00\xd8\x33\xcb\x0c\x5e\x74\x2d\x3e\x72\xdb\x67\x53\x2b\
\x48\x1a\x40\xad\xcc\x98\x99\x59\x85\x99\xb7\xde\x3f\xb4\xe6\x03\
\x95\x25\xfd\xc3\x01\xc0\x1d\x00\xad\xb2\xce\xe7\xc5\xcb\x27\x08\
\xaf\xef\xb4\x8f\x26\x11\xdd\x9b\xef\xd1\x20\x02\x6a\xe5\x26\xde\
\x7a\x63\xea\x8c\x3d\x70\xf6\xa3\xd2\xd9\xa3\xd3\x9b\xd4\xe9\xd3\
\x97\xac\xbf\x70\x59\x5a\xd1\x9c\x5e\x4c\x42\x69\xaa\x77\x3e\x35\
\xf4\xcc\xbe\x5d\xef\x4d\x5d\x75\x8b\xde\xbe\xe2\x62\x03\xb1\x1d\
\xdb\xe7\xc5\x67\x8f\x11\xf6\xef\x76\xdb\xc4\xa9\x6f\x3b\x97\xe2\
\xdf\x07\x4e\xe2\xf0\xd4\x09\x9c\x3c\x3e\x0b\xef\xf8\x7f\x02\x00\
\x1a\xc7\x5f\xfb\xea\xea\x53\x6f\x7e\xee\x8b\x37\xde\xe4\xea\x41\
\x53\x51\x8e\x55\xbe\x81\x9b\xfe\x7a\xe0\xb7\x49\x43\x5e\x98\x78\
\xc9\xd8\x5c\x10\xfc\x74\xf9\x2a\x03\x76\x2d\xdb\xf3\x01\xe6\x8e\
\x69\xbc\xfd\xbc\xff\x7e\x75\x36\x7e\x70\x6a\xe2\x28\xc6\x0f\x4c\
\xa3\xd9\x48\x16\xff\x4b\xf6\x5f\x0e\x03\xe0\x44\x28\xb5\x89\xaf\
\xd6\x63\xae\x42\xbc\x2d\x0a\x62\x16\x9d\xbc\xbc\x73\x1c\x17\xae\
\x19\x7a\x2c\xaa\x8c\x36\x6f\xb8\x6d\xe9\x8e\x91\x35\xca\x10\x19\
\x94\x8f\x05\x78\xe5\x0f\xd5\xef\xbc\xbd\xf7\xbd\x87\x27\xdf\x39\
\xb2\x48\xf8\xff\x01\x00\x00\xb6\xd6\x9e\x4a\x6d\x7a\x24\x4e\xe2\
\xb2\x77\x8d\xc8\xbb\x64\xae\x56\x6b\x24\x8d\x7a\xda\x73\xf0\xc0\
\xfb\x34\x71\xe0\xe4\x2f\x0e\xbd\xb3\xca\xdc\xfd\xdd\xcb\x1f\x0b\
\x43\x63\x7e\xb5\xed\xe0\xf7\x5e\x7f\x79\x62\x9b\x73\xae\xb7\xfd\
\xf3\x9f\x95\x6f\x15\x03\x90\xff\x15\xc0\x36\x1a\xcd\x37\xcb\xe5\
\x72\xed\xb5\x7f\xee\xe5\xc9\x89\x71\x2e\x97\x67\xa2\x77\xc6\xa7\
\xd7\x00\x58\x06\x40\x0b\x84\xde\xda\x7b\x78\xfc\xe7\x0f\x61\x7b\
\x2e\x17\x0c\xed\x7d\x65\xf2\x6f\x00\x36\x2d\x10\x9f\x17\x4e\x01\
\xc4\x00\x4e\x03\x38\xf2\x9f\x01\x00\x7c\x97\x4a\xe1\x34\x7b\x75\
\xb6\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
"
qt_resource_name = "\
\x00\x07\
\x07\x3b\xe0\xb3\
\x00\x70\
\x00\x6c\x00\x75\x00\x67\x00\x69\x00\x6e\x00\x73\
\x00\x09\
\x0a\xa8\xd2\x62\
\x00\x69\
\x00\x6e\x00\x73\x00\x74\x00\x61\x00\x6c\x00\x6c\x00\x65\x00\x72\
\x00\x10\
\x05\xc8\x49\xa7\
\x00\x72\
\x00\x65\x00\x70\x00\x6f\x00\x44\x00\x69\x00\x73\x00\x61\x00\x62\x00\x6c\x00\x65\x00\x64\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x11\
\x0f\x1e\xdc\xe7\
\x00\x72\
\x00\x65\x00\x70\x00\x6f\x00\x43\x00\x6f\x00\x6e\x00\x6e\x00\x65\x00\x63\x00\x74\x00\x65\x00\x64\x00\x2e\x00\x70\x00\x6e\x00\x67\
\
\x00\x13\
\x0b\xb7\x61\x47\
\x00\x72\
\x00\x65\x00\x70\x00\x6f\x00\x55\x00\x6e\x00\x61\x00\x76\x00\x61\x00\x69\x00\x6c\x00\x61\x00\x62\x00\x6c\x00\x65\x00\x2e\x00\x70\
\x00\x6e\x00\x67\
\x00\x0d\
\x09\xa1\x91\x67\
\x00\x71\
\x00\x67\x00\x69\x00\x73\x00\x2d\x00\x69\x00\x63\x00\x6f\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x13\
\x06\x9f\x85\x27\
\x00\x50\
\x00\x6c\x00\x75\x00\x67\x00\x69\x00\x6e\x00\x49\x00\x6e\x00\x73\x00\x74\x00\x61\x00\x6c\x00\x6c\x00\x65\x00\x72\x00\x2e\x00\x70\
\x00\x6e\x00\x67\
"
qt_resource_struct = "\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
\x00\x00\x00\x14\x00\x02\x00\x00\x00\x05\x00\x00\x00\x03\
\x00\x00\x00\x2c\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x00\xc6\x00\x00\x00\x00\x00\x01\x00\x00\x0c\x26\
\x00\x00\x00\xa6\x00\x00\x00\x00\x00\x01\x00\x00\x09\x11\
\x00\x00\x00\x7a\x00\x00\x00\x00\x00\x01\x00\x00\x05\x7f\
\x00\x00\x00\x52\x00\x00\x00\x00\x00\x01\x00\x00\x01\xe6\
"
def qInitResources():
QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
def qCleanupResources():
QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
qInitResources()

View File

@ -0,0 +1,89 @@
""" unzip.py
Version: 1.1
By Doug Tolton (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252508)
"""
import zipfile
import os
class unzip:
""" unzip.py
Version: 1.1
Extract a zipfile to the directory provided
It first creates the directory structure to house the files
then it extracts the files to it.
import unzip
un = unzip.unzip()
un.extract(r'c:\testfile.zip', 'c:\testoutput')
By Doug Tolton (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252508)
"""
def __init__(self, verbose = True, percent = 10):
self.verbose = verbose
self.percent = percent
def extract(self, file, dir):
if not dir.endswith(':') and not os.path.exists(dir):
os.mkdir(dir)
zf = zipfile.ZipFile(file)
# create directory structure to house files
#print "Creating plugin structure:"
self._createstructure(file, dir)
num_files = len(zf.namelist())
percent = self.percent
divisions = 100 / percent
perc = int(num_files / divisions)
# extract files to directory structure
for i, name in enumerate(zf.namelist()):
if self.verbose == True:
pass
#print "Extracting %s" % name
elif perc > 0 and (i % perc) == 0 and i > 0:
complete = int (i / perc) * percent
#print "%s%% complete" % complete
if not name.endswith('/'):
outfile = open(os.path.join(dir, name), 'wb')
outfile.write(zf.read(name))
outfile.flush()
outfile.close()
def _createstructure(self, file, dir):
self._makedirs(self._listdirs(file), dir)
def _makedirs(self, directories, basedir):
""" Create any directories that don't currently exist """
#print "Processing directories contained in the zip file: %s" % directories
for dir in directories:
curdir = os.path.join(basedir, dir)
# normalize the path
curdir = os.path.normpath(curdir)
#print "Checking to see if we should create %s" % curdir
if not os.path.exists(curdir):
# use makedirs to create parent directories as well
#print "Creating %s" % curdir
os.makedirs(curdir)
def _listdirs(self, file):
""" Grabs all the directories in the zip structure
This is necessary to create the structure before trying
to extract the file to it. """
zf = zipfile.ZipFile(file)
dirs = []
for name in zf.namelist():
(path, filename) = os.path.split(name)
if path not in dirs:
dirs.append(path)
dirs.sort()
return dirs