Merge branch 'master' of git://ichi2.net/ankiqt

This commit is contained in:
Susanna Björverud 2009-04-23 18:02:39 +02:00
commit 4852c42611
11 changed files with 116 additions and 67 deletions

View file

@ -75,6 +75,7 @@ class Config(dict):
'showStudyOptions': False, 'showStudyOptions': False,
'showStudyStats': True, 'showStudyStats': True,
'showCardTimer': True, 'showCardTimer': True,
'standaloneWindows': True,
'extraNewCards': 5, 'extraNewCards': 5,
'randomizeOnCram': True, 'randomizeOnCram': True,
'created': time.time(), 'created': time.time(),

View file

@ -22,7 +22,11 @@ class FocusButton(QPushButton):
class AddCards(QDialog): class AddCards(QDialog):
def __init__(self, parent): def __init__(self, parent):
QDialog.__init__(self, parent, Qt.Window) if parent.config['standaloneWindows']:
windParent = None
else:
windParent = parent
QDialog.__init__(self, windParent, Qt.Window)
self.parent = parent self.parent = parent
self.config = parent.config self.config = parent.config
self.dialog = ankiqt.forms.addcards.Ui_AddCards() self.dialog = ankiqt.forms.addcards.Ui_AddCards()

View file

@ -278,7 +278,11 @@ class StatusDelegate(QItemDelegate):
class EditDeck(QMainWindow): class EditDeck(QMainWindow):
def __init__(self, parent): def __init__(self, parent):
QMainWindow.__init__(self, parent) if parent.config['standaloneWindows']:
windParent = None
else:
windParent = parent
QMainWindow.__init__(self, windParent)
self.parent = parent self.parent = parent
self.deck = self.parent.deck self.deck = self.parent.deck
self.config = parent.config self.config = parent.config
@ -412,8 +416,7 @@ class EditDeck(QMainWindow):
self.sortKey = ("field", self.sortFields[idx-9]) self.sortKey = ("field", self.sortFields[idx-9])
self.rebuildSortIndex(self.sortKey) self.rebuildSortIndex(self.sortKey)
self.sortIndex = idx self.sortIndex = idx
if self.deck.getInt('sortIndex') != idx: self.deck.setVar('sortIndex', idx)
self.deck.setVar('sortIndex', idx)
self.model.sortKey = self.sortKey self.model.sortKey = self.sortKey
self.model.updateHeader() self.model.updateHeader()
if refresh: if refresh:
@ -499,6 +502,8 @@ class EditDeck(QMainWindow):
self.updateSearch() self.updateSearch()
def updateSearch(self, force=True): def updateSearch(self, force=True):
if self.parent.inDbHandler:
return
idx = self.dialog.tableView.currentIndex() idx = self.dialog.tableView.currentIndex()
row = idx.row() row = idx.row()
self.model.searchStr = unicode(self.dialog.filterEdit.text()) self.model.searchStr = unicode(self.dialog.filterEdit.text())

View file

@ -235,7 +235,7 @@ class DeckProperties(QDialog):
v = float(self.dialog.delay2.text()) v = float(self.dialog.delay2.text())
self.updateField(self.d, 'delay2', v) self.updateField(self.d, 'delay2', v)
v = int(self.dialog.failedCardMax.text()) v = int(self.dialog.failedCardMax.text())
self.updateField(self.d, 'failedCardMax', max(v, 5)) self.updateField(self.d, 'failedCardMax', v)
except ValueError: except ValueError:
pass pass
# hour shift # hour shift

View file

@ -42,9 +42,10 @@ class AnkiFigureCanvas (FigureCanvas):
class AdjustableFigure(QWidget): class AdjustableFigure(QWidget):
def __init__(self, config, name, figureFunc, choices=None): def __init__(self, parent, name, figureFunc, choices=None):
QWidget.__init__(self) QWidget.__init__(self)
self.config = config self.parent = parent
self.config = parent.config
self.name = name self.name = name
self.vbox = QVBoxLayout() self.vbox = QVBoxLayout()
self.vbox.setSpacing(2) self.vbox.setSpacing(2)
@ -75,6 +76,8 @@ class AdjustableFigure(QWidget):
self.vbox.addLayout(self.hbox) self.vbox.addLayout(self.hbox)
def updateFigure(self): def updateFigure(self):
if self.parent.inDbHandler:
return
self.updateTimer = None self.updateTimer = None
self.setUpdatesEnabled(False) self.setUpdatesEnabled(False)
idx = self.vbox.indexOf(self.figureCanvas) idx = self.vbox.indexOf(self.figureCanvas)
@ -184,43 +187,43 @@ class GraphWindow(object):
self.diag.show() self.diag.show()
def setupGraphs(self): def setupGraphs(self):
nextDue = AdjustableFigure(self.parent.config, 'due', self.dg.nextDue, self.range) nextDue = AdjustableFigure(self.parent, 'due', self.dg.nextDue, self.range)
nextDue.addWidget(QLabel(_("<h1>Due</h1>"))) nextDue.addWidget(QLabel(_("<h1>Due</h1>")))
self.vbox.addWidget(nextDue) self.vbox.addWidget(nextDue)
self.widgets.append(nextDue) self.widgets.append(nextDue)
workload = AdjustableFigure(self.parent.config, 'reps', self.dg.workDone, self.range) workload = AdjustableFigure(self.parent, 'reps', self.dg.workDone, self.range)
workload.addWidget(QLabel(_("<h1>Reps</h1>"))) workload.addWidget(QLabel(_("<h1>Reps</h1>")))
self.vbox.addWidget(workload) self.vbox.addWidget(workload)
self.widgets.append(workload) self.widgets.append(workload)
times = AdjustableFigure(self.parent.config, 'times', self.dg.timeSpent, self.range) times = AdjustableFigure(self.parent, 'times', self.dg.timeSpent, self.range)
times.addWidget(QLabel(_("<h1>Review Time</h1>"))) times.addWidget(QLabel(_("<h1>Review Time</h1>")))
self.vbox.addWidget(times) self.vbox.addWidget(times)
self.widgets.append(times) self.widgets.append(times)
added = AdjustableFigure(self.parent.config, 'added', self.dg.addedRecently, self.range) added = AdjustableFigure(self.parent, 'added', self.dg.addedRecently, self.range)
added.addWidget(QLabel(_("<h1>Added</h1>"))) added.addWidget(QLabel(_("<h1>Added</h1>")))
self.vbox.addWidget(added) self.vbox.addWidget(added)
self.widgets.append(added) self.widgets.append(added)
answered = AdjustableFigure(self.parent.config, 'answered', lambda *args: apply( answered = AdjustableFigure(self.parent, 'answered', lambda *args: apply(
self.dg.addedRecently, args + ('firstAnswered',)), self.range) self.dg.addedRecently, args + ('firstAnswered',)), self.range)
answered.addWidget(QLabel(_("<h1>First Answered</h1>"))) answered.addWidget(QLabel(_("<h1>First Answered</h1>")))
self.vbox.addWidget(answered) self.vbox.addWidget(answered)
self.widgets.append(answered) self.widgets.append(answered)
cumDue = AdjustableFigure(self.parent.config, 'cum', self.dg.cumulativeDue, self.range) cumDue = AdjustableFigure(self.parent, 'cum', self.dg.cumulativeDue, self.range)
cumDue.addWidget(QLabel(_("<h1>Cumulative Due</h1>"))) cumDue.addWidget(QLabel(_("<h1>Cumulative Due</h1>")))
self.vbox.addWidget(cumDue) self.vbox.addWidget(cumDue)
self.widgets.append(cumDue) self.widgets.append(cumDue)
interval = AdjustableFigure(self.parent.config, 'interval', self.dg.intervalPeriod, self.range) interval = AdjustableFigure(self.parent, 'interval', self.dg.intervalPeriod, self.range)
interval.addWidget(QLabel(_("<h1>Intervals</h1>"))) interval.addWidget(QLabel(_("<h1>Intervals</h1>")))
self.vbox.addWidget(interval) self.vbox.addWidget(interval)
self.widgets.append(interval) self.widgets.append(interval)
eases = AdjustableFigure(self.parent.config, 'eases', self.dg.easeBars) eases = AdjustableFigure(self.parent, 'eases', self.dg.easeBars)
eases.addWidget(QLabel(_("<h1>Eases</h1>"))) eases.addWidget(QLabel(_("<h1>Eases</h1>")))
self.vbox.addWidget(eases) self.vbox.addWidget(eases)
self.widgets.append(eases) self.widgets.append(eases)

View file

@ -134,6 +134,8 @@ class ImportDialog(QDialog):
txt = ( txt = (
_("Importing complete. %(num)d facts imported from %(file)s.\n") % _("Importing complete. %(num)d facts imported from %(file)s.\n") %
{"num": self.importer.total, "file": os.path.basename(self.file)}) {"num": self.importer.total, "file": os.path.basename(self.file)})
self.dialog.groupBox.setShown(False)
self.dialog.buttonBox.button(QDialogButtonBox.Close).setFocus()
if self.importer.log: if self.importer.log:
txt += _("Log of import:\n") + "\n".join(self.importer.log) txt += _("Log of import:\n") + "\n".join(self.importer.log)
self.dialog.status.setText(txt) self.dialog.status.setText(txt)

View file

@ -14,7 +14,7 @@ from PyQt4.QtGui import *
from anki import DeckStorage from anki import DeckStorage
from anki.errors import * from anki.errors import *
from anki.sound import hasSound, playFromText, clearAudioQueue from anki.sound import hasSound, playFromText, clearAudioQueue
from anki.utils import addTags, deleteTags, parseTags from anki.utils import addTags, deleteTags, parseTags, canonifyTags
from anki.media import rebuildMediaDir from anki.media import rebuildMediaDir
from anki.db import OperationalError from anki.db import OperationalError
from anki.stdmodels import BasicModel from anki.stdmodels import BasicModel
@ -685,8 +685,7 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
def onClose(self): def onClose(self):
if self.inMainWindow(): if self.inMainWindow():
cramming = self.deck is not None and self.deck.name() == "cram" self.saveAndClose(hideWelcome=self.isCramming())
self.saveAndClose(hideWelcome=cramming)
if cramming: if cramming:
self.loadRecent(0) self.loadRecent(0)
else: else:
@ -830,14 +829,17 @@ To upgrade an old deck, download Anki 0.9.8.7."""))
self.updateRecentFiles(file) self.updateRecentFiles(file)
return True return True
def onUnsavedTimer(self): def showToolTip(self, msg):
t = QTimer(self)
t.setSingleShot(True)
t.start(200)
self.connect(t, SIGNAL("timeout()"),
lambda msg=msg: self._showToolTip(msg))
def _showToolTip(self, msg):
QToolTip.showText( QToolTip.showText(
self.mainWin.statusbar.mapToGlobal(QPoint(0, -100)), self.mainWin.statusbar.mapToGlobal(QPoint(0, -40)),
_("""\ msg)
<h1>Unsaved Deck</h1>
Careful. You're editing an unsaved Deck.<br>
Choose File -> Save to start autosaving<br>
your deck."""))
def save(self, required=False): def save(self, required=False):
if not self.deck.path: if not self.deck.path:
@ -845,10 +847,11 @@ your deck."""))
# backed in memory, make sure it's saved # backed in memory, make sure it's saved
return self.onSaveAs() return self.onSaveAs()
else: else:
t = QTimer(self) self.showToolTip(_("""\
t.setSingleShot(True) <h1>Unsaved Deck</h1>
t.start(200) Careful. You're editing an unsaved Deck.<br>
self.connect(t, SIGNAL("timeout()"), self.onUnsavedTimer) Choose File -> Save to start autosaving<br>
your deck."""))
return return
if not self.deck.modifiedSinceSave(): if not self.deck.modifiedSinceSave():
return True return True
@ -1036,7 +1039,6 @@ your deck."""))
def updateStudyStats(self): def updateStudyStats(self):
wasReached = self.deck.sessionLimitReached() wasReached = self.deck.sessionLimitReached()
self.deck.sessionStartTime = 0
sessionColour = '<font color=#0000ff>%s</font>' sessionColour = '<font color=#0000ff>%s</font>'
cardColour = '<font color=#0000ff>%s</font>' cardColour = '<font color=#0000ff>%s</font>'
if not wasReached: if not wasReached:
@ -1155,8 +1157,21 @@ day = :d""", d=yesterday)
int(self.mainWin.questionLimit.text())) int(self.mainWin.questionLimit.text()))
except (ValueError, OverflowError): except (ValueError, OverflowError):
pass pass
uf(self.deck, 'newCardOrder', ncOrd = self.mainWin.newCardOrder.currentIndex()
self.mainWin.newCardOrder.currentIndex()) if self.deck.newCardOrder != ncOrd:
if self.deck.newCardOrder == 0 and ncOrd != 0:
# random to non-random
self.deck.startProgress()
self.deck.updateProgress(_("Ordering..."))
self.deck.orderNewCards()
self.deck.finishProgress()
elif self.deck.newCardOrder != 0 and ncOrd == 0:
# non-random to random
self.deck.startProgress()
self.deck.updateProgress(_("Randomizing..."))
self.deck.randomizeNewCards()
self.deck.finishProgress()
uf(self.deck, 'newCardOrder', ncOrd)
uf(self.deck, 'newCardSpacing', uf(self.deck, 'newCardSpacing',
self.mainWin.newCardScheduling.currentIndex()) self.mainWin.newCardScheduling.currentIndex())
uf(self.deck, 'revCardOrder', uf(self.deck, 'revCardOrder',
@ -1315,11 +1330,11 @@ day = :d""", d=yesterday)
def onMark(self, toggled): def onMark(self, toggled):
if self.currentCard.hasTag("Marked"): if self.currentCard.hasTag("Marked"):
self.currentCard.fact.tags = deleteTags( self.currentCard.fact.tags = canonifyTags(deleteTags(
"Marked", self.currentCard.fact.tags) "Marked", self.currentCard.fact.tags))
else: else:
self.currentCard.fact.tags = addTags( self.currentCard.fact.tags = canonifyTags(addTags(
"Marked", self.currentCard.fact.tags) "Marked", self.currentCard.fact.tags))
self.currentCard.fact.setModified(textChanged=True) self.currentCard.fact.setModified(textChanged=True)
self.deck.updateFactTags([self.currentCard.fact.id]) self.deck.updateFactTags([self.currentCard.fact.id])
self.deck.setModified() self.deck.setModified()
@ -1327,7 +1342,8 @@ day = :d""", d=yesterday)
def onSuspend(self): def onSuspend(self):
undo = _("Suspend") undo = _("Suspend")
self.deck.setUndoStart(undo) self.deck.setUndoStart(undo)
self.currentCard.fact.tags = addTags("Suspended", self.currentCard.fact.tags) self.currentCard.fact.tags = canonifyTags(
addTags("Suspended", self.currentCard.fact.tags))
self.currentCard.fact.setModified(textChanged=True) self.currentCard.fact.setModified(textChanged=True)
self.deck.updateFactTags([self.currentCard.fact.id]) self.deck.updateFactTags([self.currentCard.fact.id])
for card in self.currentCard.fact.cards: for card in self.currentCard.fact.cards:
@ -1358,10 +1374,19 @@ day = :d""", d=yesterday)
########################################################################## ##########################################################################
def onAddCard(self): def onAddCard(self):
if self.isCramming():
ui.utils.showInfo(_("""\
You are currently cramming. Please close this deck first."""))
return
ui.dialogs.get("AddCards", self) ui.dialogs.get("AddCards", self)
def onEditDeck(self): def onEditDeck(self):
ui.dialogs.get("CardList", self) ui.dialogs.get("CardList", self)
if self.isCramming():
self.showToolTip(_("""\
<h1>Cramming</h1>
You are currently cramming. Any edits you make to this deck
will be lost when you close the deck."""))
def onEditCurrent(self): def onEditCurrent(self):
self.moveToState("editCurrentFact") self.moveToState("editCurrentFact")
@ -1397,7 +1422,10 @@ day = :d""", d=yesterday)
########################################################################## ##########################################################################
def onImport(self): def onImport(self):
import ui.importing if self.isCramming():
ui.utils.showInfo(_("""\
You are currently cramming. Please close this deck first."""))
return
if self.deck is None: if self.deck is None:
self.onNew() self.onNew()
ui.importing.ImportDialog(self) ui.importing.ImportDialog(self)
@ -1421,8 +1449,11 @@ day = :d""", d=yesterday)
e.exportInto(path) e.exportInto(path)
return (e, path) return (e, path)
def isCramming(self):
return self.deck is not None and self.deck.name() == "cram"
def onCram(self, cardIds=[]): def onCram(self, cardIds=[]):
if self.deck.name() == "cram": if self.isCramming():
ui.utils.showInfo( ui.utils.showInfo(
_("Already cramming. Please close this deck first.")) _("Already cramming. Please close this deck first."))
return return
@ -1442,7 +1473,7 @@ day = :d""", d=yesterday)
ui.utils.showInfo(_("No cards matched the provided tags.")) ui.utils.showInfo(_("No cards matched the provided tags."))
return return
if self.config['randomizeOnCram']: if self.config['randomizeOnCram']:
n = 5 n = 3
else: else:
n = 2 n = 2
p = ui.utils.ProgressWin(self, n, 0, _("Cram")) p = ui.utils.ProgressWin(self, n, 0, _("Cram"))
@ -1462,22 +1493,11 @@ day = :d""", d=yesterday)
self.deck.easyIntervalMax = 0.25 self.deck.easyIntervalMax = 0.25
self.deck.newCardOrder = 0 self.deck.newCardOrder = 0
self.deck.syncName = None self.deck.syncName = None
p.update()
self.deck.updateDynamicIndices()
if self.config['randomizeOnCram']: if self.config['randomizeOnCram']:
p.update(_("Randomizing...")) p.update(_("Randomizing..."))
self.deck.s.statement( self.deck.randomizeNewCards()
"create temporary table idmap (old, new, primary key (old))")
self.deck.s.statement(
"insert into idmap select id, random() from facts")
self.deck.s.statement(
"update facts set id = (select new from idmap where old = id)")
p.update()
self.deck.s.statement(
"update cards set factId = (select new from idmap where old = factId)")
p.update()
self.deck.s.statement(
"update fields set factId = (select new from idmap where old = factId)")
p.update()
self.deck.updateDynamicIndices()
self.reset() self.reset()
p.finish() p.finish()
@ -1645,6 +1665,7 @@ it to your friends.
onlyMerge, self.sourcesToCheck) onlyMerge, self.sourcesToCheck)
self.connect(self.syncThread, SIGNAL("setStatus"), self.setSyncStatus) self.connect(self.syncThread, SIGNAL("setStatus"), self.setSyncStatus)
self.connect(self.syncThread, SIGNAL("showWarning"), self.showSyncWarning) self.connect(self.syncThread, SIGNAL("showWarning"), self.showSyncWarning)
self.connect(self.syncThread, SIGNAL("noSyncResponse"), self.noSyncResponse)
self.connect(self.syncThread, SIGNAL("moveToState"), self.moveToState) self.connect(self.syncThread, SIGNAL("moveToState"), self.moveToState)
self.connect(self.syncThread, SIGNAL("noMatchingDeck"), self.selectSyncDeck) self.connect(self.syncThread, SIGNAL("noMatchingDeck"), self.selectSyncDeck)
self.connect(self.syncThread, SIGNAL("syncClockOff"), self.syncClockOff) self.connect(self.syncThread, SIGNAL("syncClockOff"), self.syncClockOff)
@ -1719,6 +1740,11 @@ it to your friends.
ui.utils.showWarning(text, self) ui.utils.showWarning(text, self)
self.setStatus("") self.setStatus("")
def noSyncResponse(self):
self.showToolTip(_("""\
<h1>Sync Failed</h1>
Couldn't contact Anki Online. Please check your internet connection."""))
def openSyncProgress(self): def openSyncProgress(self):
self.syncProgressDialog = QProgressDialog(_("Syncing Media..."), self.syncProgressDialog = QProgressDialog(_("Syncing Media..."),
"", 0, 0, self) "", 0, 0, self)

View file

@ -64,13 +64,16 @@ class StatusView(object):
shown = True shown = True
self.progressBar.setShown(shown) self.progressBar.setShown(shown)
self.retentionBar.setShown(shown) self.retentionBar.setShown(shown)
self.timer.setShown(shown)
self.etaText.setShown(shown) self.etaText.setShown(shown)
self.remText.setShown(shown) self.remText.setShown(shown)
self.sep1.setShown(shown) self.sep1.setShown(shown)
self.sep2.setShown(shown) self.sep2.setShown(shown)
self.sep3.setShown(shown)
self.statusbar.hideOrShow() self.statusbar.hideOrShow()
# timer has a separate option
if not self.main.config['showTimer']:
shown = False
self.timer.setShown(shown)
self.sep3.setShown(shown)
# Setup and teardown # Setup and teardown
########################################################################## ##########################################################################
@ -130,8 +133,6 @@ class StatusView(object):
self.timer.setText("00:00") self.timer.setText("00:00")
self.addWidget(self.timer) self.addWidget(self.timer)
self.redraw() self.redraw()
if not self.main.config['showTimer']:
self.timer.setShown(False)
def addWidget(self, w, stretch=0): def addWidget(self, w, stretch=0):
self.statusbar.addWidget(w, stretch) self.statusbar.addWidget(w, stretch)

View file

@ -36,8 +36,11 @@ class Sync(QThread):
self.syncDeck() self.syncDeck()
def error(self, error): def error(self, error):
error = self.getErrorMessage(error) if error.data.get('type') == 'noResponse':
self.emit(SIGNAL("showWarning"), error) self.emit(SIGNAL("noSyncResponse"))
else:
error = self.getErrorMessage(error)
self.emit(SIGNAL("showWarning"), error)
if self.onlyMerge: if self.onlyMerge:
# new file needs cleaning up # new file needs cleaning up
self.emit(SIGNAL("cleanNewDeck")) self.emit(SIGNAL("cleanNewDeck"))
@ -50,11 +53,7 @@ class Sync(QThread):
elif error.data.get('status') == "oldVersion": elif error.data.get('status') == "oldVersion":
msg=_("The sync protocol has changed. Please upgrade.") msg=_("The sync protocol has changed. Please upgrade.")
else: else:
msg=_("""\ msg=_("Unknown error: %s" % `getattr(error, 'data')`)
Syncing failed. Please try again in a few minutes.
If the problem persists, please report it on the forum.
Error: %s""" % `getattr(error, 'data')`)
return msg return msg
def connect(self, *args): def connect(self, *args):

View file

@ -12,6 +12,10 @@
<property name="windowTitle" > <property name="windowTitle" >
<string>Add Items</string> <string>Add Items</string>
</property> </property>
<property name="windowIcon" >
<iconset resource="../icons.qrc" >
<normaloff>:/icons/list-add.png</normaloff>:/icons/list-add.png</iconset>
</property>
<layout class="QVBoxLayout" name="verticalLayout" > <layout class="QVBoxLayout" name="verticalLayout" >
<property name="spacing" > <property name="spacing" >
<number>0</number> <number>0</number>
@ -93,8 +97,8 @@
<string>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <string>&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css"> &lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;style type="text/css">
p, li { white-space: pre-wrap; } p, li { white-space: pre-wrap; }
&lt;/style>&lt;/head>&lt;body style=" font-family:'Arial'; font-size:8pt; font-weight:400; font-style:normal;"> &lt;/style>&lt;/head>&lt;body style=" font-family:'Sans Serif'; font-size:8pt; font-weight:400; font-style:normal;">
&lt;p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&lt;/p>&lt;/body>&lt;/html></string> &lt;p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Arial';">&lt;/p>&lt;/body>&lt;/html></string>
</property> </property>
</widget> </widget>
</widget> </widget>

View file

@ -12,6 +12,10 @@
<property name="windowTitle" > <property name="windowTitle" >
<string>Browse Items</string> <string>Browse Items</string>
</property> </property>
<property name="windowIcon" >
<iconset resource="../icons.qrc" >
<normaloff>:/icons/find.png</normaloff>:/icons/find.png</iconset>
</property>
<widget class="QWidget" name="centralwidget" > <widget class="QWidget" name="centralwidget" >
<layout class="QVBoxLayout" name="verticalLayout" > <layout class="QVBoxLayout" name="verticalLayout" >
<property name="spacing" > <property name="spacing" >