Merge pull request #4675 from alexbruy/processing-help

[processing] improve help system
This commit is contained in:
Alexander Bruy 2017-06-06 13:08:22 +03:00 committed by GitHub
commit 80911c6e74
11 changed files with 216 additions and 193 deletions

View File

@ -44,7 +44,7 @@ from processing.gui.ConfigDialog import ConfigOptionsPage
from processing.gui.ResultsDock import ResultsDock from processing.gui.ResultsDock import ResultsDock
from processing.gui.AlgorithmLocatorFilter import AlgorithmLocatorFilter from processing.gui.AlgorithmLocatorFilter import AlgorithmLocatorFilter
from processing.modeler.ModelerDialog import ModelerDialog from processing.modeler.ModelerDialog import ModelerDialog
from processing.tools.system import tempFolder from processing.tools.system import tempFolder, tempHelpFolder
from processing.gui.menus import removeMenus, initializeMenus, createMenus from processing.gui.menus import removeMenus, initializeMenus, createMenus
from processing.core.ProcessingResults import resultsList from processing.core.ProcessingResults import resultsList
@ -146,6 +146,11 @@ class ProcessingPlugin(object):
if QDir(folder).exists(): if QDir(folder).exists():
shutil.rmtree(folder, True) shutil.rmtree(folder, True)
# also delete temporary help files
folder = tempHelpFolder()
if QDir(folder).exists():
shutil.rmtree(folder, True)
self.iface.unregisterMainWindowAction(self.toolboxAction) self.iface.unregisterMainWindowAction(self.toolboxAction)
self.iface.unregisterMainWindowAction(self.modelerAction) self.iface.unregisterMainWindowAction(self.modelerAction)
self.iface.unregisterMainWindowAction(self.historyAction) self.iface.unregisterMainWindowAction(self.historyAction)

View File

@ -80,19 +80,15 @@ class GdalAlgorithm(GeoAlgorithm):
commands[i] = c commands[i] = c
GdalUtils.runGdal(commands, feedback) GdalUtils.runGdal(commands, feedback)
def shortHelpString(self): def helpUrl(self):
helpPath = GdalUtils.gdalHelpPath() helpPath = GdalUtils.gdalHelpPath()
if helpPath == '': if helpPath == '':
return return None
if os.path.exists(helpPath): if os.path.exists(helpPath):
url = QUrl.fromLocalFile(os.path.join(helpPath, '{}.html'.format(self.commandName()))).toString() return QUrl.fromLocalFile(os.path.join(helpPath, '{}.html'.format(self.commandName()))).toString()
else: else:
url = helpPath + '{}.html'.format(self.commandName()) return helpPath + '{}.html'.format(self.commandName())
return '''This algorithm is based on the GDAL {} module.
For more info, see the <a href={}> module help</a>
'''.format(self.commandName(), url)
def commandName(self): def commandName(self):
parameters = {} parameters = {}

View File

@ -25,6 +25,9 @@ __copyright__ = '(C) 2012, Victor Olaya'
__revision__ = '$Format:%H$' __revision__ = '$Format:%H$'
from builtins import str
from builtins import object
import os.path import os.path
import traceback import traceback
import subprocess import subprocess
@ -39,9 +42,8 @@ from qgis.core import (QgsProcessingFeedback,
QgsProcessingUtils, QgsProcessingUtils,
QgsProcessingParameterDefinition, QgsProcessingParameterDefinition,
QgsMessageLog) QgsMessageLog)
from qgis.gui import QgsHelp
from builtins import str
from builtins import object
from processing.core.ProcessingConfig import ProcessingConfig from processing.core.ProcessingConfig import ProcessingConfig
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterRaster, ParameterVector, ParameterMultipleInput, ParameterTable, Parameter from processing.core.parameters import ParameterRaster, ParameterVector, ParameterMultipleInput, ParameterTable, Parameter
@ -390,3 +392,7 @@ def executeAlgorithm(alg, parameters, context=None, feedback=None, model=None):
# lines.append(traceback.format_exc()) # lines.append(traceback.format_exc())
#QgsMessageLog.logMessage('\n'.join(lines), self.tr('Processing'), QgsMessageLog.CRITICAL) #QgsMessageLog.logMessage('\n'.join(lines), self.tr('Processing'), QgsMessageLog.CRITICAL)
#raise GeoAlgorithmExecutionException(str(e) + self.tr('\nSee log for more details'), lines, e) #raise GeoAlgorithmExecutionException(str(e) + self.tr('\nSee log for more details'), lines, e)
def helpUrl(self):
return QgsHelp.helpUrl("processing_algs/{}/{}".format(
self.provider().id(), self.id())).toString()

View File

@ -157,7 +157,7 @@ class AlgorithmDialog(AlgorithmDialogBase):
return hasExtent and unmatchingCRS return hasExtent and unmatchingCRS
def accept(self): def accept(self):
self.settings.setValue("/Processing/dialogBase", self.saveGeometry()) super(AlgorithmDialog, self)._saveGeometry()
context = dataobjects.createContext() context = dataobjects.createContext()
@ -273,7 +273,7 @@ class AlgorithmDialog(AlgorithmDialogBase):
self.tr('HTML output has been generated by this algorithm.' self.tr('HTML output has been generated by this algorithm.'
'\nOpen the results dialog to check it.')) '\nOpen the results dialog to check it.'))
def closeEvent(self, evt): def closeEvent(self, event):
QgsProject.instance().layerWasAdded.disconnect(self.mainWidget.layerRegistryChanged) QgsProject.instance().layerWasAdded.disconnect(self.mainWidget.layerRegistryChanged)
QgsProject.instance().layersWillBeRemoved.disconnect(self.mainWidget.layerRegistryChanged) QgsProject.instance().layersWillBeRemoved.disconnect(self.mainWidget.layerRegistryChanged)
super(AlgorithmDialog, self).closeEvent(evt) super(AlgorithmDialog, self).closeEvent(event)

View File

@ -30,13 +30,11 @@ import os
import webbrowser import webbrowser
from qgis.PyQt import uic from qgis.PyQt import uic
from qgis.PyQt.QtCore import QCoreApplication, QByteArray, QUrl from qgis.PyQt.QtCore import Qt, QCoreApplication, QByteArray, QUrl
from qgis.PyQt.QtWidgets import QApplication, QDialogButtonBox from qgis.PyQt.QtWidgets import QApplication, QDialogButtonBox, QVBoxLayout, QToolButton
from qgis.PyQt.QtNetwork import QNetworkRequest, QNetworkReply
from qgis.utils import iface from qgis.utils import iface
from qgis.core import (QgsNetworkAccessManager, from qgis.core import (QgsProject,
QgsProject,
QgsProcessingFeedback, QgsProcessingFeedback,
QgsSettings) QgsSettings)
@ -82,17 +80,37 @@ class AlgorithmDialogBase(BASE, WIDGET):
super(AlgorithmDialogBase, self).__init__(iface.mainWindow()) super(AlgorithmDialogBase, self).__init__(iface.mainWindow())
self.setupUi(self) self.setupUi(self)
# don't collapse parameters panel
self.splitter.setCollapsible(0, False)
# add collapse button to splitter
splitterHandle = self.splitter.handle(1)
handleLayout = QVBoxLayout()
handleLayout.setContentsMargins(0, 0, 0, 0)
self.btnCollapse = QToolButton(splitterHandle)
self.btnCollapse.setAutoRaise(True)
self.btnCollapse.setFixedSize(12, 12)
self.btnCollapse.setCursor(Qt.ArrowCursor)
handleLayout.addWidget(self.btnCollapse)
handleLayout.addStretch()
splitterHandle.setLayout(handleLayout)
self.feedback = AlgorithmDialogFeedback(self) self.feedback = AlgorithmDialogFeedback(self)
self.feedback.progressChanged.connect(self.setPercentage) self.feedback.progressChanged.connect(self.setPercentage)
self.buttonCancel.clicked.connect(self.feedback.cancel) self.buttonCancel.clicked.connect(self.feedback.cancel)
self.settings = QgsSettings() self.settings = QgsSettings()
self.splitter.restoreState(self.settings.value("/Processing/dialogBaseSplitter", QByteArray()))
self.restoreGeometry(self.settings.value("/Processing/dialogBase", QByteArray())) self.restoreGeometry(self.settings.value("/Processing/dialogBase", QByteArray()))
self.splitterState = self.splitter.saveState()
self.splitterChanged(0, 0)
self.executed = False self.executed = False
self.mainWidget = None self.mainWidget = None
self.alg = alg self.alg = alg
self.setWindowTitle(self.alg.displayName())
# Rename OK button to Run # Rename OK button to Run
self.btnRun = self.buttonBox.button(QDialogButtonBox.Ok) self.btnRun = self.buttonBox.button(QDialogButtonBox.Ok)
self.btnRun.setText(self.tr('Run')) self.btnRun.setText(self.tr('Run'))
@ -100,8 +118,10 @@ class AlgorithmDialogBase(BASE, WIDGET):
self.buttonCancel.setEnabled(False) self.buttonCancel.setEnabled(False)
self.btnClose = self.buttonBox.button(QDialogButtonBox.Close) self.btnClose = self.buttonBox.button(QDialogButtonBox.Close)
self.buttonBox.helpRequested.connect(self.openHelp)
self.setWindowTitle(self.alg.displayName()) self.btnCollapse.clicked.connect(self.toggleCollapsed)
self.splitter.splitterMoved.connect(self.splitterChanged)
# desktop = QDesktopWidget() # desktop = QDesktopWidget()
# if desktop.physicalDpiX() > 96: # if desktop.physicalDpiX() > 96:
@ -109,7 +129,7 @@ class AlgorithmDialogBase(BASE, WIDGET):
algHelp = self.formatHelp(self.alg) algHelp = self.formatHelp(self.alg)
if algHelp is None: if algHelp is None:
self.textShortHelp.setVisible(False) self.textShortHelp.hide()
else: else:
self.textShortHelp.document().setDefaultStyleSheet('''.summary { margin-left: 10px; margin-right: 10px; } self.textShortHelp.document().setDefaultStyleSheet('''.summary { margin-left: 10px; margin-right: 10px; }
h2 { color: #555555; padding-bottom: 15px; } h2 { color: #555555; padding-bottom: 15px; }
@ -119,30 +139,11 @@ class AlgorithmDialogBase(BASE, WIDGET):
dl dd { margin-bottom: 5px; }''') dl dd { margin-bottom: 5px; }''')
self.textShortHelp.setHtml(algHelp) self.textShortHelp.setHtml(algHelp)
self.textShortHelp.setOpenLinks(False)
def linkClicked(url): def linkClicked(url):
webbrowser.open(url.toString()) webbrowser.open(url.toString())
self.textShortHelp.anchorClicked.connect(linkClicked) self.textShortHelp.anchorClicked.connect(linkClicked)
if self.alg.helpString() is not None:
try:
self.txtHelp.setHtml(self.alg.helpString())
except Exception:
self.tabWidget.removeTab(2)
elif self.alg.helpUrl() is not None:
try:
html = self.tr('<p>Downloading algorithm help... Please wait.</p>')
self.txtHelp.setHtml(html)
rq = QNetworkRequest(QUrl(self.alg.helpUrl()))
self.reply = QgsNetworkAccessManager.instance().get(rq)
self.reply.finished.connect(self.requestFinished)
except Exception:
self.tabWidget.removeTab(2)
else:
self.tabWidget.removeTab(2)
self.showDebug = ProcessingConfig.getSetting( self.showDebug = ProcessingConfig.getSetting(
ProcessingConfig.SHOW_DEBUG_IN_DIALOG) ProcessingConfig.SHOW_DEBUG_IN_DIALOG)
@ -152,19 +153,9 @@ class AlgorithmDialogBase(BASE, WIDGET):
return None return None
return "<h2>%s</h2>%s" % (alg.displayName(), "".join(["<p>%s</p>" % s for s in text.split("\n")])) return "<h2>%s</h2>%s" % (alg.displayName(), "".join(["<p>%s</p>" % s for s in text.split("\n")]))
def requestFinished(self): def closeEvent(self, event):
"""Change the webview HTML content""" self._saveGeometry()
reply = self.sender() super(AlgorithmDialogBase, self).closeEvent(event)
if reply.error() != QNetworkReply.NoError:
html = self.tr('<h2>No help available for this algorithm</h2><p>{}</p>'.format(reply.errorString()))
else:
html = str(reply.readAll())
reply.deleteLater()
self.txtHelp.setHtml(html)
def closeEvent(self, evt):
self.settings.setValue("/Processing/dialogBase", self.saveGeometry())
super(AlgorithmDialogBase, self).closeEvent(evt)
def setMainWidget(self, widget): def setMainWidget(self, widget):
if self.mainWidget is not None: if self.mainWidget is not None:
@ -228,9 +219,40 @@ class AlgorithmDialogBase(BASE, WIDGET):
def accept(self): def accept(self):
pass pass
def reject(self):
self._saveGeometry()
super(AlgorithmDialogBase, self).reject()
def finish(self, context): def finish(self, context):
pass pass
def toggleCollapsed(self):
if self.helpCollapsed:
self.splitter.restoreState(self.splitterState)
self.btnCollapse.setArrowType(Qt.RightArrow)
else:
self.splitterState = self.splitter.saveState()
self.splitter.setSizes([1, 0])
self.btnCollapse.setArrowType(Qt.LeftArrow)
self.helpCollapsed = not self.helpCollapsed
def splitterChanged(self, pos, index):
if self.splitter.sizes()[1] == 0:
self.helpCollapsed = True
self.btnCollapse.setArrowType(Qt.LeftArrow)
else:
self.helpCollapsed = False
self.btnCollapse.setArrowType(Qt.RightArrow)
def openHelp(self):
algHelp = self.alg.helpUrl()
if algHelp not in [None, ""]:
webbrowser.open(algHelp)
def _saveGeometry(self):
self.settings.setValue("/Processing/dialogBaseSplitter", self.splitter.saveState())
self.settings.setValue("/Processing/dialogBase", self.saveGeometry())
class InvalidParameterValue(Exception): class InvalidParameterValue(Exception):
def __init__(self, param, widget): def __init__(self, param, widget):

View File

@ -27,11 +27,14 @@ __copyright__ = '(C) 2012, Victor Olaya'
__revision__ = '$Format:%H$' __revision__ = '$Format:%H$'
from qgis.PyQt.QtCore import QCoreApplication
import os import os
import re import re
import json import json
from qgis.PyQt.QtCore import QCoreApplication, QUrl
from processing.tools import system
ALG_DESC = 'ALG_DESC' ALG_DESC = 'ALG_DESC'
ALG_CREATOR = 'ALG_CREATOR' ALG_CREATOR = 'ALG_CREATOR'
ALG_HELP_CREATOR = 'ALG_HELP_CREATOR' ALG_HELP_CREATOR = 'ALG_HELP_CREATOR'
@ -63,7 +66,13 @@ def getHtmlFromHelpFile(alg, helpFile):
try: try:
with open(helpFile) as f: with open(helpFile) as f:
descriptions = json.load(f) descriptions = json.load(f)
return getHtmlFromDescriptionsDict(alg, descriptions)
content = getHtmlFromDescriptionsDict(alg, descriptions)
algGroup, algName = alg.id().split(':')
filePath = os.path.join(system.tempHelpFolder(), "{}_{}.html".format(algGroup, algName))
with open(filePath, 'w', encoding='utf-8') as f:
f.write(content)
return QUrl.fromLocalFile(filePath).toString()
except: except:
return None return None

View File

@ -539,7 +539,7 @@ class ModelerAlgorithm(GeoAlgorithm):
if self.modelerdialog: if self.modelerdialog:
self.modelerdialog.repaintModel() self.modelerdialog.repaintModel()
def helpString(self): def helpUrl(self):
try: try:
return getHtmlFromDescriptionsDict(self, self.helpContent) return getHtmlFromDescriptionsDict(self, self.helpContent)
except: except:

View File

@ -27,15 +27,14 @@ __copyright__ = '(C) 2012, Victor Olaya'
__revision__ = '$Format:%H$' __revision__ = '$Format:%H$'
import webbrowser
from qgis.PyQt.QtCore import Qt, QUrl, QMetaObject from qgis.PyQt.QtCore import Qt, QUrl, QMetaObject
from qgis.PyQt.QtWidgets import (QDialog, QDialogButtonBox, QLabel, QLineEdit, from qgis.PyQt.QtWidgets import (QDialog, QDialogButtonBox, QLabel, QLineEdit,
QFrame, QPushButton, QSizePolicy, QVBoxLayout, QFrame, QPushButton, QSizePolicy, QVBoxLayout,
QHBoxLayout, QTabWidget, QWidget, QHBoxLayout, QWidget)
QTextBrowser)
from qgis.PyQt.QtNetwork import QNetworkRequest, QNetworkReply
from qgis.core import (QgsNetworkAccessManager, from qgis.core import (QgsProcessingParameterDefinition)
QgsProcessingParameterDefinition)
from qgis.gui import (QgsMessageBar, from qgis.gui import (QgsMessageBar,
QgsScrollArea) QgsScrollArea)
@ -89,7 +88,8 @@ class ModelerParametersDialog(QDialog):
self.buttonBox = QDialogButtonBox() self.buttonBox = QDialogButtonBox()
self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setOrientation(Qt.Horizontal)
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel |
QDialogButtonBox.Ok) + QDialogButtonBox.Ok |
+ QDialogButtonBox.Help)
self.setSizePolicy(QSizePolicy.Expanding, self.setSizePolicy(QSizePolicy.Expanding,
QSizePolicy.Expanding) QSizePolicy.Expanding)
self.verticalLayout = QVBoxLayout() self.verticalLayout = QVBoxLayout()
@ -182,53 +182,24 @@ class ModelerParametersDialog(QDialog):
self.verticalLayout2 = QVBoxLayout() self.verticalLayout2 = QVBoxLayout()
self.verticalLayout2.setSpacing(2) self.verticalLayout2.setSpacing(2)
self.verticalLayout2.setMargin(0) self.verticalLayout2.setMargin(0)
self.tabWidget = QTabWidget()
self.tabWidget.setMinimumWidth(300)
self.paramPanel = QWidget() self.paramPanel = QWidget()
self.paramPanel.setLayout(self.verticalLayout) self.paramPanel.setLayout(self.verticalLayout)
self.scrollArea = QgsScrollArea() self.scrollArea = QgsScrollArea()
self.scrollArea.setWidget(self.paramPanel) self.scrollArea.setWidget(self.paramPanel)
self.scrollArea.setWidgetResizable(True) self.scrollArea.setWidgetResizable(True)
self.tabWidget.addTab(self.scrollArea, self.tr('Parameters'))
self.txtHelp = QTextBrowser() self.verticalLayout2.addWidget(self.scrollArea)
html = None
isText, algHelp = self._alg.help()
if algHelp is not None:
algHelp = algHelp if isText else QUrl(algHelp)
try:
if isText:
self.txtHelp.setHtml(algHelp)
else:
html = self.tr('<p>Downloading algorithm help... Please wait.</p>')
self.txtHelp.setHtml(html)
self.tabWidget.addTab(self.txtHelp, 'Help')
self.reply = QgsNetworkAccessManager.instance().get(QNetworkRequest(algHelp))
self.reply.finished.connect(self.requestFinished)
except:
pass
self.verticalLayout2.addWidget(self.tabWidget)
self.verticalLayout2.addWidget(self.buttonBox) self.verticalLayout2.addWidget(self.buttonBox)
self.setLayout(self.verticalLayout2) self.setLayout(self.verticalLayout2)
self.buttonBox.accepted.connect(self.okPressed) self.buttonBox.accepted.connect(self.okPressed)
self.buttonBox.rejected.connect(self.cancelPressed) self.buttonBox.rejected.connect(self.cancelPressed)
self.buttonBox.helpRequested.connect(self.openHelp)
QMetaObject.connectSlotsByName(self) QMetaObject.connectSlotsByName(self)
for wrapper in list(self.wrappers.values()): for wrapper in list(self.wrappers.values()):
wrapper.postInitialize(list(self.wrappers.values())) wrapper.postInitialize(list(self.wrappers.values()))
def requestFinished(self):
"""Change the webview HTML content"""
reply = self.sender()
if reply.error() != QNetworkReply.NoError:
html = self.tr('<h2>No help available for this algorithm</h2><p>{}</p>'.format(reply.errorString()))
else:
html = str(reply.readAll())
reply.deleteLater()
self.txtHelp.setHtml(html)
def getAvailableDependencies(self): # spellok def getAvailableDependencies(self): # spellok
if self._algName is None: if self._algName is None:
dependent = [] dependent = []
@ -353,3 +324,8 @@ class ModelerParametersDialog(QDialog):
def cancelPressed(self): def cancelPressed(self):
self.alg = None self.alg = None
self.close() self.close()
def openHelp(self):
algHelp = self._alg.help()
if algHelp is not None:
webbrowser.open(algHelp)

View File

@ -198,9 +198,9 @@ class ScriptAlgorithm(GeoAlgorithm):
for out in self.outputs: for out in self.outputs:
out.setValue(ns[out.name]) out.setValue(ns[out.name])
def helpString(self): def helpUrl(self):
if self.descriptionFile is None: if self.descriptionFile is None:
return False, None return None
helpfile = self.descriptionFile + '.help' helpfile = self.descriptionFile + '.help'
if os.path.exists(helpfile): if os.path.exists(helpfile):
return getHtmlFromHelpFile(self, helpfile) return getHtmlFromHelpFile(self, helpfile)

View File

@ -142,6 +142,14 @@ def mkdir(newdir):
os.mkdir(newdir) os.mkdir(newdir)
def tempHelpFolder():
tmp = os.path.join(str(QDir.tempPath()), 'processing_help')
if not QDir(tmp).exists():
QDir().mkpath(tmp)
return str(os.path.abspath(tmp))
def escapeAndJoin(strList): def escapeAndJoin(strList):
joined = '' joined = ''
for s in strList: for s in strList:

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>841</width> <width>685</width>
<height>525</height> <height>525</height>
</rect> </rect>
</property> </property>
@ -15,9 +15,26 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <widget class="QSplitter" name="splitter">
<item> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="handleWidth">
<number>16</number>
</property>
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>2</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>0</number>
</property> </property>
@ -63,21 +80,10 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item> <property name="topMargin">
<widget class="QTextEdit" name="txtLog"> <number>0</number>
<property name="readOnly">
<bool>true</bool>
</property> </property>
</widget> <property name="rightMargin">
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Help</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number> <number>0</number>
</property> </property>
<property name="leftMargin"> <property name="leftMargin">
@ -93,35 +99,30 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="QTextBrowser" name="txtHelp"/> <widget class="QTextEdit" name="txtLog">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
</item>
<item>
<widget class="QTextBrowser" name="textShortHelp"> <widget class="QTextBrowser" name="textShortHelp">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="minimumSize"> <property name="accessibleName">
<size> <string/>
<width>200</width>
<height>0</height>
</size>
</property> </property>
<property name="maximumSize"> <property name="openLinks">
<size> <bool>false</bool>
<width>300</width>
<height>16777215</height>
</size>
</property> </property>
</widget> </widget>
</item> </widget>
</layout>
</item> </item>
<item> <item>
<widget class="QLabel" name="lblProgress"> <widget class="QLabel" name="lblProgress">
@ -157,7 +158,7 @@
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="standardButtons"> <property name="standardButtons">
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set> <set>QDialogButtonBox::Close|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
</property> </property>
</widget> </widget>
</item> </item>