Refactor: Split config objects to Gui and Probe
[mentor.git] / src / mentor.py
blobe0f5bc3691817e8442417a636840b50668a9197a
1 #!/usr/bin/env python
2 # -*- coding: iso-8859-2 -*-
4 # Copyright (C) 2007 Adam Folmert <afolmert@gmail.com>
6 # This file is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2, or (at your option)
9 # any later version.
11 # This file is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 """This is mentor main program.
25 Mentor is a simple flashcard-like app with special focus on creating flashcards
26 out of text and image snippets. It's main purpose is quickly import knowledge
27 from selected snippets and transform it into knowledge by performing drills.
29 The drill is done via hiding part of the card (creating a cloze) and obscuring
30 it. The user has to think of an answer and then reveal the cloze to see if she
31 remembered it right. Then she gives herself a score (1-5) depending on how well
32 she felt to remember the cloze. The score is used to schedule the next
33 repetition period.
35 It enables text-mode and graphical-mode snippet creation and drill.
37 It also provides functionality for scheduling repetitions for created cards,
38 which is useful if one wants to make repetitions over longer time period.
40 """
44 import release
45 __author__ = '%s <%s>' % \
46 ( release.authors['afolmert'][0], release.authors['afolmert'][1])
48 __license__ = release.license
49 __version__ = release.version
51 import sys
52 import os
53 from PyQt4.QtCore import *
54 from PyQt4.QtGui import *
55 from utils_qt import lazyshow, tr, show_info, propagate_fonts
56 from utils import log, run_command
57 from config import gui_config as config
58 from models import CardModel, DrillModel
59 from cards import Card
60 from views import CardContentView, CardMainView, CardGridView
63 # generate mentor_rc if does not exist
64 try:
65 import mentor_rc
66 except:
67 run_command(["pyrcc4", "mentor.qrc"], "mentor_rc.py")
68 try:
69 import mentor_rc
70 except:
71 error("File mentor.qrc not found!")
77 class DrillWindow(QDialog):
78 def __init__(self, parent=None):
79 QDialog.__init__(self, parent)
81 self.setWindowTitle('Mentor Drill')
83 self.model = DrillModel(self)
85 self.currentCard = Card()
89 # card view
90 self.cardView = CardMainView()
93 # card list view
94 self.cardListView = QListView(self)
95 self.cardListView.setModel(self.model)
96 self.cardListView.setMinimumWidth(200)
97 self.cardListView.setVisible(False)
100 self.splitter = QSplitter(Qt.Horizontal)
101 self.splitter.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
102 self.splitter.addWidget(self.cardView)
103 self.splitter.addWidget(self.cardListView)
104 self.splitter.setSizes([400, 200])
107 # buttons bar
108 self.buttons = QWidget(self)
110 self.btnNext = QPushButton("&1. Next card")
111 self.btnShowAnswer = QPushButton("&2. Show answer")
112 self.btnGoodScore = QPushButton("&3. Good score")
113 self.btnBadScore = QPushButton("&4. Bad score")
114 self.btnShuffleCards = QPushButton("&5. Shuffle cards")
115 self.btnPrintCards = QPushButton("&6. Print cards")
116 self.btnClose = QPushButton("&7. Close")
118 # todo move this to actions
119 self.connect(self.btnNext, SIGNAL('clicked()'), self.on_btnNext_clicked)
120 self.connect(self.btnShowAnswer, SIGNAL('clicked()'), self.on_btnShowAnswer_clicked)
121 self.connect(self.btnGoodScore, SIGNAL('clicked()'), self.on_btnGoodScore_clicked)
122 self.connect(self.btnBadScore, SIGNAL('clicked()'), self.on_btnBadScore_clicked)
123 self.connect(self.btnShuffleCards, SIGNAL('clicked()'), self.on_btnShuffleCards_clicked)
124 self.connect(self.btnPrintCards, SIGNAL('clicked()'), self.on_btnPrintCards_clicked)
125 self.connect(self.btnClose, SIGNAL('clicked()'), self.on_btnClose_clicked)
127 buttonsLayout = QHBoxLayout()
129 buttonsLayout.addWidget(self.btnNext)
130 buttonsLayout.addWidget(self.btnShowAnswer)
131 buttonsLayout.addWidget(self.btnGoodScore)
132 buttonsLayout.addWidget(self.btnBadScore)
133 buttonsLayout.addWidget(self.btnShuffleCards)
134 buttonsLayout.addWidget(self.btnPrintCards)
135 buttonsLayout.addWidget(self.btnClose)
137 self.buttons.setLayout(buttonsLayout)
139 layout = QVBoxLayout()
140 layout.setSpacing(1)
141 layout.setMargin(1)
142 layout.addWidget(self.splitter)
143 layout.addWidget(self.buttons)
144 self.setLayout(layout)
146 self.setGeometry(100, 100, 500, 500)
148 self.cardView.displayCard(self.currentCard)
150 propagate_fonts(self, config.GUI_FONT)
153 def loadCards(self, cards):
154 """Loads a list of cards to model."""
155 for card in cards:
156 self.model.addCard(card)
157 self.currentCard = self.model.selectNextCard()
158 self.cardView.displayCard(self.currentCard, True, False)
160 def on_btnNext_clicked(self):
161 self.currentCard = self.model.selectNextCard()
162 self.cardView.displayCard(self.currentCard, True, False)
164 def on_btnShowAnswer_clicked(self):
165 self.cardView.displayCard(self.currentCard, True, True)
167 def on_btnGoodScore_clicked(self):
168 self.model.scoreCard(self.currentCard, DrillModel.Good)
170 def on_btnBadScore_clicked(self):
171 self.model.scoreCard(self.currentCard, DrillModel.Bad)
173 def on_btnShuffleCards_clicked(self):
174 self.model.shuffleCards()
175 self.currentCard = self.model.selectNextCard()
176 self.cardView.displayCard(self.currentCard, True, False)
178 def on_btnPrintCards_clicked(self):
179 self.model.printCards()
181 def on_btnClose_clicked(self):
182 self.close()
184 def keyPressEvent(self, event):
185 if event.key == Qt.Key_F8:
186 self.cardListView.setVisible(not self.cardListView.visible())
187 event.accept()
188 else:
189 event.ignore()
191 def event(self, event):
192 if isinstance(event, QKeyEvent) and event.key() == Qt.Key_F8:
193 self.cardListView.setVisible(not self.cardListView.isVisible())
194 return True
195 return QDialog.event(self, event)
198 class OptionsDialog(QDialog):
199 """Dialog for setting Mentor preferences."""
200 def __init__(self, parent=None):
201 QDialog.__init__(self, parent)
203 self.setWindowTitle("Options")
205 layout = QGridLayout()
207 list = QListWidget()
208 layout.addWidget(list, 0, 0, 5, 1)
209 list.addItem(QListWidgetItem(QIcon(QPixmap(":images/star.png")), "Startup"))
210 list.addItem(QListWidgetItem(QIcon(QPixmap(":images/book.png")), "Interface"))
211 list.addItem(QListWidgetItem(QIcon(QPixmap(":images/find.png")), "Learning"))
212 list.addItem(QListWidgetItem(QIcon(QPixmap(":images/next.png")), "Items"))
213 list.addItem(QListWidgetItem(QIcon(QPixmap(":images/previous.png")), "Advanced"))
214 list.addItem(QListWidgetItem(QIcon(QPixmap(":images/zoomin.png")), "Connection"))
215 list.addItem(QListWidgetItem(QIcon(QPixmap(":images/zoomout.png")), "Plugins"))
218 list.setFixedWidth(120)
219 list.setMinimumWidth(120)
220 list.setMaximumWidth(120)
221 list.setViewMode(QListView.IconMode)
222 list.setMovement(QListView.Static)
223 list.setSpacing(10)
224 list.setFlow(QListView.TopToBottom)
227 tab = QTabWidget()
228 tab.addTab(self.createTableWidget(), "Tab 1")
229 tab.addTab(self.createTableWidget(), "Tab 2")
230 tab.addTab(self.createButtonsWidget(), "Tab 3")
232 blayout = QHBoxLayout()
233 btnOk = QPushButton("OK")
234 btnOk.setMaximumHeight(25)
235 btnCancel = QPushButton("Cancel")
236 btnCancel.setMaximumHeight(25)
237 blayout.addItem(QSpacerItem(150, 25, QSizePolicy.Fixed, QSizePolicy.Fixed))
238 blayout.addWidget(btnOk)
239 blayout.addWidget(btnCancel)
240 blayout.setSpacing(0)
241 blayout.setMargin(0)
243 self.connect(btnOk, SIGNAL('clicked()'), SLOT('close()'))
244 self.connect(btnCancel, SIGNAL('clicked()'), SLOT('close()'))
246 layout.addWidget(tab, 0, 1, 5, 1)
249 mainlayout = QVBoxLayout()
250 mainlayout.addLayout(layout)
251 mainlayout.addLayout(blayout)
252 self.setLayout(mainlayout)
255 propagate_fonts(self, config.GUI_FONT)
259 def buttonClicked(self):
260 log('button was clicked!')
263 def createButtonsWidget(self):
264 w = QWidget()
265 l = QVBoxLayout()
266 b = QPushButton("Hello", w)
267 t = QTextEdit()
268 l.addWidget(b)
269 l.addWidget(t)
270 self.connect(b, SIGNAL('clicked()'), self.buttonClicked)
271 w.setLayout(l)
272 return w
275 def createTableWidget(self):
276 w = QWidget()
277 g = QGridLayout()
278 for x in range(3):
279 for y in range(3):
280 t = QTabWidget()
281 g.addWidget(t, x, y)
282 g.setSpacing(0)
283 g.setMargin(0)
284 w.setLayout(g)
285 return w
298 class MainWindow(QMainWindow):
299 """Central window for the Mentor app"""
301 def __init__(self, parent = None):
302 QMainWindow.__init__(self, parent)
304 config.load()
306 self.setFont(config.GUI_FONT)
308 # set up controls
309 # items panel
310 self._cardModel = CardModel()
311 self._cardModelIndex = QModelIndex() # current index for card model
313 self.setWindowTitle("Mentor")
314 self.setWindowIcon(QIcon(QPixmap(":/images/mentor.png")))
315 self.setGeometry(config.GUI_GEOMETRY)
316 if config.GUI_MAXIMIZED:
317 self.setWindowState(Qt.WindowMaximized)
319 self.createCentralWidget()
320 self.createActions()
321 self.createMenus()
322 self.createToolbars()
323 self.createStatusBar()
326 propagate_fonts(self, config.GUI_FONT)
328 self.connect(qApp, SIGNAL('aboutToQuit()'), self.qApp_aboutToQuit)
330 QTimer.singleShot(0, self._openRecentFile)
334 def createCentralWidget(self):
336 self.gridView = CardGridView(self)
337 self.gridView.setModel(self._cardModel)
339 self.contentView = CardContentView(self)
340 self.contentView.setModel(self._cardModel)
343 self.splitter = QSplitter(Qt.Horizontal)
344 self.splitter.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
346 self.splitter.addWidget(self.gridView)
347 self.splitter.addWidget(self.contentView)
348 self.splitter.setSizes([200, 500])
350 self.setCentralWidget(self.splitter)
354 ##########################
355 # connecting
356 # FIXME connecting these 4 times cause sometimes I don't get proper
357 # messages
358 # when I edit something and press Down
359 # and then click on what I edited then selection changed does not catch
360 # it
362 self.connect(self.gridView.selectionModel(), \
363 SIGNAL('currentChanged(QModelIndex, QModelIndex)'), \
364 self.gridView_currentChanged)
365 self.connect(self.gridView,
366 SIGNAL('activated(QModelIndex)'), \
367 self.gridView_activated)
368 self.connect(self.gridView,
369 SIGNAL('clicked(QModelIndex)'), \
370 self.gridView_activated)
372 self.connect(self, SIGNAL('cardModelIndexChanged'), self.gridView_cardModelIndexChanged)
373 self.connect(self, SIGNAL('cardModelIndexChanged'), self.contentView.currentChanged)
378 def cardModel(self):
379 return self._cardModel
381 def setCardModel(self, model):
382 self._cardModel = model
384 def cardModelIndex(self):
385 return self._cardModelIndex
387 def setCardModelIndex(self, index):
388 old = self._cardModelIndex
389 # if old != index:
390 self._cardModelIndex = index
391 self.emit(SIGNAL('cardModelIndexChanged'), index, old)
394 def createActions(self):
395 # File actions
396 self.actNewDeck = QAction(tr("&New deck..."), self)
397 self.actNewDeck.setStatusTip(tr("Create a new deck..."))
398 self.connect(self.actNewDeck, SIGNAL("triggered()"), self.on_actNewDeck_triggered)
400 self.actOpenDeck = QAction(tr("&Open deck..."), self)
401 self.actOpenDeck.setShortcut(QKeySequence(tr("Ctrl+O")))
402 self.actOpenDeck.setStatusTip(tr("Open an existing deck..."))
403 self.connect(self.actOpenDeck, SIGNAL("triggered()"), self.on_actOpenDeck_triggered)
404 self.actCloseDeck = QAction(tr("&Close deck"), self)
405 self.actCloseDeck.setStatusTip(tr("Close currently active deck"))
406 self.connect(self.actCloseDeck, SIGNAL("triggered()"), self.on_actCloseDeck_triggered)
407 self.actCopyDeck = QAction(tr("&Copy deck..."), self)
408 self.actCopyDeck.setStatusTip(tr("Copy an existing deck..."))
409 self.connect(self.actCopyDeck, SIGNAL("triggered()"), self.on_actCopyDeck_triggered)
410 self.actDeleteDeck = QAction(tr("&Delete deck..."), self)
411 self.actDeleteDeck.setStatusTip(tr("Delete an existing deck..."))
412 self.connect(self.actDeleteDeck, SIGNAL("triggered()"), self.on_actDeleteDeck_triggered)
413 self.actRepairDeck = QAction(tr("&Repair deck..."), self)
414 self.actRepairDeck.setStatusTip(tr("Repair an existing deck..."))
415 self.connect(self.actRepairDeck, SIGNAL("triggered()"), self.on_actRepairDeck_triggered)
416 self.actMergeDeck = QAction(tr("&Merge deck..."), self)
417 self.actMergeDeck.setStatusTip(tr("Merge an existing deck..."))
418 self.connect(self.actMergeDeck, SIGNAL("triggered()"), self.on_actMergeDeck_triggered)
419 self.actImportQA = QAction(tr("&Import from QA file..."), self)
420 self.actImportQA.setStatusTip(tr("Import from QA file..."))
421 self.connect(self.actImportQA, SIGNAL("triggered()"), self.on_actImportQA_triggered)
422 self.actImportXML = QAction(tr("&Import from XML file..."), self)
423 self.actImportXML.setStatusTip(tr("Import from XML file..."))
424 self.connect(self.actImportXML, SIGNAL("triggered()"), self.on_actImportXML_triggered)
425 self.actImportProbe = QAction(tr("&Import from PRB file..."), self)
426 self.actImportProbe.setStatusTip(tr("Import from a PRB file..."))
427 self.connect(self.actImportProbe, SIGNAL("triggered()"), self.on_actImportProbe_triggered)
428 self.actImportSuperMemo = QAction(tr("&Import from SuperMemo..."), self)
429 self.actImportProbe.setStatusTip(tr("Import from a SuperMemo..."))
430 self.connect(self.actImportProbe, SIGNAL("triggered()"), self.on_actImportProbe_triggered)
431 self.actExportQA = QAction(tr("&Export to QA file..."), self)
432 self.actExportQA.setStatusTip(tr("Export to QA file..."))
433 self.connect(self.actExportQA, SIGNAL("triggered()"), self.on_actExportQA_triggered)
434 self.actExportXML = QAction(tr("&Export to XML file..."), self)
435 self.actExportXML.setStatusTip(tr("Export to XML file..."))
436 self.connect(self.actExportXML, SIGNAL("triggered()"), self.on_actExportXML_triggered)
437 self.actExportProbe = QAction(tr("&Export to PRB file..."), self)
438 self.actExportProbe.setStatusTip(tr("Export to PRB file..."))
439 self.connect(self.actExportProbe, SIGNAL("triggered()"), self.on_actExportProbe_triggered)
440 self.actExportSuperMemo = QAction(tr("&Export to SuperMemo..."), self)
441 self.actExportProbe.setStatusTip(tr("Export to SuperMemo..."))
442 self.connect(self.actExportProbe, SIGNAL("triggered()"), self.on_actExportProbe_triggered)
443 self.actProperties = QAction(tr("&Properties..."), self)
444 self.actExportProbe.setStatusTip(tr("Display deck properties..."))
445 self.connect(self.actExportProbe, SIGNAL("triggered()"), self.on_actExportProbe_triggered)
446 # Recent file actions
447 self.actRecentFiles = []
448 for i in range(config.GUI_RECENTFILES_MAX):
449 self.actRecentFiles.append(QAction(self))
450 self.actRecentFiles[i].setVisible(False)
451 self.connect(self.actRecentFiles[i], SIGNAL("triggered()"), self.on_actRecentFiles_triggered)
453 self.actExit = QAction(tr("E&xit"), self)
454 self.actExit.setShortcut(QKeySequence(tr("Ctrl+Q")))
455 self.actExit.setStatusTip(tr("Exits the application."))
456 self.connect(self.actExit, SIGNAL("triggered()"), qApp, SLOT("quit()"))
458 # Edit actions
459 self.actUndo = QAction(tr("&Undo"), self)
460 self.actUndo.setShortcut(QKeySequence(tr("Ctrl+Z")))
461 self.actRedo = QAction(tr("Re&do"), self)
462 self.actRedo.setShortcut(QKeySequence(tr("Ctrl+Y")))
463 self.actCut = QAction(tr("Cu&t"), self)
464 self.actCut.setShortcut(QKeySequence(tr("Ctrl+X")))
465 self.actCopy = QAction(tr("&Copy"), self)
466 self.actUndo.setShortcut(QKeySequence(tr("Ctrl+C")))
467 self.actPaste = QAction(tr("&Paste"), self)
468 self.actPaste.setShortcut(QKeySequence(tr("Ctrl+V")))
469 self.actCutAppend = QAction(tr("Cut and append"), self)
470 self.actCutAppend.setShortcut(QKeySequence(tr("Ctrl+Shift+X")))
471 self.actCopyAppend = QAction(tr("Copy and append"), self)
472 self.actCopyAppend.setShortcut(QKeySequence(tr("Ctrl+Shift+C")))
473 self.actSelectAll = QAction(tr("Select &all"), self)
474 self.actSelectAll.setShortcut(QKeySequence(tr("Ctrl+A")))
475 self.actSelectLine = QAction(tr("Select &line"), self)
476 self.actSelectWord = QAction(tr("Select &word"), self)
477 self.actSelectWord.setShortcut(QKeySequence(tr("Ctrl+J")))
478 self.actDelete = QAction(tr("&Delete"), self)
479 self.actDelete.setShortcut(QKeySequence(tr("DEL")))
480 self.actDeleteLine = QAction(tr("&Delete &line"), self)
481 self.actDeleteLine.setShortcut(QKeySequence(tr("Ctrl+E")))
482 self.actDeleteToStartLine = QAction(tr("Delete to &start of line"), self)
483 self.actDeleteToStartLine.setShortcut(QKeySequence(tr("Ctrl+F11")))
484 self.actDeleteToEndLine = QAction(tr("Delete to &end of line"), self)
485 self.actDeleteToEndLine.setShortcut(QKeySequence(tr("Ctrl+F12")))
489 # Cards actions
490 self.actFirstCard = QAction(tr("&First"), self)
491 self.actFirstCard.setShortcut(QKeySequence("Shift+Ctrl+PgUp"))
492 self.connect(self.actFirstCard, SIGNAL("triggered()"), self.on_actFirstCard_triggered)
493 self.actPreviousCard = QAction(tr("&Previous"), self)
494 self.actPreviousCard.setShortcut(QKeySequence("Ctrl+PgUp"))
495 self.connect(self.actPreviousCard, SIGNAL("triggered()"), self.on_actPreviousCard_triggered)
496 self.actNextCard = QAction(tr("&Next"), self)
497 self.actNextCard.setShortcut(QKeySequence("Ctrl+PgDown"))
498 self.connect(self.actNextCard, SIGNAL("triggered()"), self.on_actNextCard_triggered)
499 self.actLastCard = QAction(tr("&Last"), self)
500 self.actLastCard.setShortcut(QKeySequence("Shift+Ctrl+PgDown"))
501 self.connect(self.actLastCard, SIGNAL("triggered()"), self.on_actLastCard_triggered)
503 self.actAddCard = QAction(tr("&Add"), self)
504 self.actAddCard.setShortcut(QKeySequence(tr("Ctrl+N")))
505 self.connect(self.actAddCard, SIGNAL("triggered()"), self.on_actAddCard_triggered)
506 self.actInsertCard = QAction(tr("&Insert"), self)
507 self.actInsertCard.setShortcut(QKeySequence(tr("Ctrl+Ins")))
508 self.connect(self.actInsertCard, SIGNAL("triggered()"), self.on_actInsertCard_triggered)
509 self.actDeleteCard = QAction(tr("&Delete"), self)
510 self.actDeleteCard.setShortcut(QKeySequence(tr("Ctrl+Del")))
511 self.connect(self.actDeleteCard, SIGNAL("triggered()"), self.on_actDeleteCard_triggered)
513 self.actSort = QAction(tr("&Sort..."), self)
514 self.actFilter = QAction(tr("&Filter..."), self)
516 # Cards action -> from Edit/SuperMemo
518 self.actNewItem = QAction(tr("Add a new i&tem"), self)
519 self.actNewItem.setShortcut(QKeySequence(tr("Alt+A")))
520 self.actNewArticle = QAction(tr("Add a new &article"), self)
521 self.actNewArticle.setShortcut(QKeySequence(tr("Ctrl+Alt+N")))
522 self.actNewTask = QAction(tr("Add a &new task"), self)
523 self.actNewTask.setShortcut(QKeySequence("Ctrl+Alt+A"))
525 # Search actions
526 self.actFindElements = QAction(tr("&Find elements"), self)
527 self.actFindElements.setShortcut(QKeySequence(tr("Ctrl+F")))
528 self.actFindTexts = QAction(tr("Fi&nd texts"), self)
529 self.actFindTexts.setShortcut(QKeySequence(tr("Ctrl+S")))
530 self.actFindWord = QAction(tr("Fin&d word"), self)
531 self.actFindString = QAction(tr("Find st&ring"), self)
532 self.actFindString.setShortcut(QKeySequence(tr("F3")))
533 self.actTextRegistry = QAction(tr("Te&xt registry"), self)
534 self.actTextRegistry.setShortcut(QKeySequence(tr("Ctrl+Alt+X")))
535 self.actImages = QAction(tr("&Images"), self)
536 self.actSounds = QAction(tr("&Sounds"), self)
537 self.actTemplates = QAction(tr("&Templates"), self)
538 self.actCategories = QAction(tr("&Categories"), self)
539 self.actTasklists = QAction(tr("Tas&klists"), self)
540 self.actOtherRegistries = QAction(tr("&Other registries"), self)
541 self.actFont = QAction(tr("&Font"), self)
542 self.actTranslation = QAction(tr("&Translation"), self)
543 self.actPronunciationByWord = QAction(tr("&Pronunciation by word"), self)
544 self.actPronunciationBySound = QAction(tr("Pronunciation by soun&d"), self)
545 self.actComment = QAction(tr("&Comment"), self)
546 self.actVideo = QAction(tr("&Video"), self)
547 self.actScript = QAction(tr("&Script"), self)
548 self.actProgram = QAction(tr("&OLE Object"), self)
549 self.actGotoAncestor = QAction(tr("Go to &ancestor"), self)
550 self.actGotoElement = QAction(tr("Go to &element"), self)
551 self.actGotoElement.setShortcut(QKeySequence(tr("Ctrl+G")))
553 # Learn actions
554 self.actLearnAllStages = QAction(tr("&All stages"), self)
555 self.actLearnAllStages.setShortcut(QKeySequence(tr("Ctrl+L")))
556 self.actLearnOutstanding = QAction(tr("1. &Outstanding material"), self)
557 self.actLearnNew = QAction(tr("2. &New material"), self)
558 self.actLearnNew.setShortcut(QKeySequence(tr("Ctrl-F2")))
559 self.actLearnFinalDrill = QAction(tr("3. &Final drill"), self)
560 self.actLearnFinalDrill.setShortcut(QKeySequence(tr("Ctrl+F2")))
561 self.connect(self.actLearnFinalDrill, SIGNAL("triggered()"), self.on_actFinalDrill_triggered)
562 self.actReadingList = QAction(tr("&Reading list"), self)
563 self.actReadingList.setShortcut(QKeySequence(tr("Shift+Ctrl+F4")))
564 self.actPostponeTopics = QAction(tr("&Topics"), self)
565 self.actPostponeItems = QAction(tr("&Items"), self)
566 self.actPostponeAll = QAction(tr("&All"), self)
567 self.actRandomizeRepetitions = QAction(tr("Randomi&ze repetitions"), self)
568 self.actRandomizeRepetitions.setShortcut(QKeySequence("Shift+Ctrl+F11"))
569 self.actRandomLearning = QAction(tr("Ran&dom learning"), self)
570 self.actRandomLearning.setShortcut(QKeySequence("Ctrl+F11"))
571 self.actCutDrills = QAction("&Cut drills", self)
573 # View actions
574 self.actAll = QAction(tr("&All"), self)
575 self.actOutstanding = QAction(tr("&Outstanding"), self)
576 self.actMemorized = QAction(tr("&Memorized"), self)
577 self.actPending = QAction(tr("&Pending"), self)
578 self.actDismissed = QAction(tr("&Dismissed"), self)
579 self.actTopic = QAction(tr("&Topic"), self)
580 self.actItems = QAction(tr("&Items"), self)
581 self.actTasks = QAction(tr("Ta&ks"), self)
582 self.actLastBrowser = QAction(tr("&Last browser"), self)
583 self.actSearchResults = QAction(tr("&Search results"), self)
584 self.actSubset = QAction(tr("S&ubset"), self)
585 self.actFilter = QAction(tr("&Filter..."), self)
586 self.actLeeches = QAction(tr("&Leeches"), self)
587 self.actLeeches.setShortcut(QKeySequence("Shift+F3"))
588 self.actSemiLeeches = QAction(tr("&Semi-leeches"), self)
589 self.actDrill = QAction(tr("&Drill"), self)
590 self.actRange = QAction(tr("&Range"), self)
591 self.actHistory = QAction(tr("&History"), self)
592 self.actBranch = QAction(tr("&Branch"), self)
594 # Tools actions
595 self.actWorkload = QAction(tr("&Workload"), self)
596 self.actWorkload.setShortcut(QKeySequence("Ctrl+W"))
597 self.actPlan = QAction(tr("&Plan"), self)
598 self.actWorkload.setShortcut(QKeySequence("Ctrl+P"))
599 self.actMercy = QAction(tr("&Mercy"), self)
600 self.actMercy.setShortcut(QKeySequence("Ctrl+Y"))
601 self.actTasklist = QAction(tr("&Tasklist"), self)
602 self.actTasklist.setShortcut(QKeySequence("F4"))
603 self.actReadingList = QAction(tr("&Reading list"), self)
604 self.actReadingList.setShortcut(QKeySequence(tr("Ctrl+F4")))
605 self.actStatistics = QAction(tr("S&tatistics"), self)
606 self.actElementData = QAction(tr("&Element data"), self)
607 self.actAnalysis = QAction(tr("&Analysis"), self)
608 self.actAnalysis.setShortcut(QKeySequence(tr("Ctrl+Alt+I")))
609 self.actSimulation = QAction(tr("&Simulation"), self)
610 self.actReport = QAction(tr("&Report"), self)
611 self.actRandomizeDrill = QAction(tr("&Drill"), self)
612 self.actRandomizePending = QAction(tr("&Pending"), self)
613 self.actRandomTest = QAction(tr("&Resume test"), self)
614 self.actRandomAll = QAction(tr("&All"), self)
615 self.actRandomAll.setShortcut(QKeySequence(tr("Alt+F11")))
616 self.actRandomPending = QAction(tr("&Pending"), self)
617 self.actRandomMemorized = QAction(tr("&Memorized"), self)
618 self.actRandomDismissed = QAction(tr("&Dismissed"), self)
619 self.actRandomTopics = QAction(tr("&Topics"), self)
620 self.actRandomItems = QAction(tr("&Items"), self)
621 self.actRandomFilter = QAction(tr("&Filter"), self)
622 self.actRandomLeeches = QAction(tr("&Leeches"), self)
623 self.actRandomSubset = QAction(tr("&Subset"), self)
624 self.actRandomBranch = QAction(tr("&Branch"), self)
625 self.actOptions = QAction(tr("&Options"), self)
626 self.actOptions.setShortcut(tr("Ctrl+Alt+O"))
627 self.connect(self.actOptions, SIGNAL("triggered()"), self.on_actOptions_triggered)
630 # Window actions
631 self.actDock = QAction(tr("&Dock"), self)
632 self.actToolbarRead = QAction(tr("&Read"), self)
633 self.actToolbarCompose = QAction("&Compose", self)
634 self.actToolbarFormat = QAction("&Format", self)
635 self.actToolbarTime = QAction("&Time", self)
636 self.actToolbarActions = QAction("&Actions", self)
637 self.actDockToolbars = QAction("&Dock toolbars", self)
638 self.actStatusBar = QAction(tr("&Status bar"), self)
639 self.actBackground = QAction(tr("&Background"), self)
640 self.actBackground.setShortcut(QKeySequence(tr("Ctrl+Alt+F10")))
641 self.actHints = QAction(tr("H&ints"), self)
642 self.actSelectCategory = QAction(tr("&Category"), self)
643 self.actSelectCategory.setShortcut(QKeySequence(tr("Ctrl+Alt+C")))
644 self.actSelectTasklist = QAction(tr("&Tasklist"), self)
645 self.actSelectTasklist.setShortcut(QKeySequence(tr("Ctrl+Alt+T")))
646 self.actSelectNextWindow = QAction(tr("&Next window"), self)
647 self.actSelectNextWindow.setShortcut(QKeySequence(tr("Ctrl+F6")))
648 self.actLayoutManager = QAction(tr("&Layout Manager"), self)
649 self.actApplyDefaultLayout = QAction(tr("&Apply default layout"), self)
650 self.actClassLayout = QAction(tr("&Class layout"), self)
651 self.actClassLayout.setShortcut(QKeySequence(tr("F5")))
652 self.actSaveCustomLayout = QAction(tr("&Save custom layout"), self)
653 self.actSaveAsDefault = QAction(tr("Sa&ve as default"), self)
654 self.actSaveAsDefault.setShortcut(QKeySequence(tr("Shift+Ctrl+F5")))
655 self.actBackgroundColor = QAction(tr("&Background color"), self)
656 self.actLayoutLastUsed = QAction(tr("Last used"), self)
657 self.actLayoutContents = QAction(tr("Contents"), self)
658 self.actLayoutClassic = QAction(tr("Classic"), self)
659 self.actLayoutBrowser = QAction(tr("Browser"), self)
661 # Help actions
662 self.actWelcome = QAction(tr("&Welcome - ABC"), self)
663 self.actGuide = QAction(tr("&Guide"), self)
664 self.actTroubleshooter = QAction(tr("&Troubleshooter"), self)
665 self.actFaq = QAction(tr("&FAQ"), self)
666 self.actHintsAndTips = QAction(tr("&Hints and tips"), self)
667 self.actContext = QAction(tr("C&ontext F1"), self)
668 self.actContext.setShortcut(QKeySequence("F1"))
669 self.actOnlineHelp = QAction(tr("&On-line help"), self)
670 self.actNews = QAction(tr("&News"), self)
671 self.actWebFaq = QAction(tr("&FAQ"), self)
672 self.actLibrary = QAction(tr("SuperMemo &Library"), self)
673 self.actSupport = QAction(tr("&Support"), self)
674 self.actBugReport = QAction(tr("&Bug report"), self)
675 self.actQuestionnaire = QAction(tr("&Questionnaire"), self)
676 self.actRecommended = QAction(tr("&Recommended SuperMemo"), self)
677 self.actQuestionOfDay = QAction(tr("&Question of the Day"), self)
678 self.actAbout = QAction(tr("&About"), self)
679 self.actAbout.setStatusTip(tr("Show the program and author information"))
681 self.connect(self.actAbout, SIGNAL("triggered()"), self.on_actAbout_triggered)
686 def createMenus(self):
687 self.menuBar().setFont(QFont("Fixed", 8))
691 # File menu
692 mnuFile = self.menuBar().addMenu(tr("&File"))
694 mnuFile.addAction(self.actNewDeck)
695 mnuFile.addAction(self.actOpenDeck)
696 mnuFile.addAction(self.actCloseDeck)
697 mnuFile.addSeparator()
698 mnuFile.addAction(self.actCopyDeck)
699 mnuFile.addAction(self.actDeleteDeck)
700 mnuFile.addAction(self.actRepairDeck)
701 mnuFile.addAction(self.actMergeDeck)
702 mnuFile.addSeparator()
703 mnuImport = mnuFile.addMenu(tr("Import"))
704 mnuImport.addAction(self.actImportQA)
705 mnuImport.addAction(self.actImportXML)
706 mnuImport.addAction(self.actImportProbe)
707 mnuImport.addAction(self.actImportSuperMemo)
708 mnuExport = mnuFile.addMenu(tr("Export"))
709 mnuExport.addAction(self.actExportQA)
710 mnuExport.addAction(self.actExportXML)
711 mnuExport.addAction(self.actExportProbe)
712 mnuExport.addAction(self.actExportSuperMemo)
713 mnuFile.addSeparator()
714 mnuFile.addAction(self.actProperties)
715 mnuFile.addSeparator()
716 for act in self.actRecentFiles:
717 mnuFile.addAction(act)
718 mnuFile.addSeparator()
719 mnuFile.addAction(self.actExit)
721 # Menu Edit
722 mnuEdit = self.menuBar().addMenu(tr("&Edit"))
723 mnuEdit.addAction(self.actUndo)
724 mnuEdit.addAction(self.actRedo)
725 mnuEdit.addSeparator()
726 mnuEdit.addAction(self.actCut)
727 mnuEdit.addAction(self.actCopy)
728 mnuEdit.addAction(self.actPaste)
729 mnuEdit.addAction(self.actCutAppend)
730 mnuEdit.addAction(self.actCopyAppend)
731 mnuEdit.addSeparator()
732 mnuEdit.addAction(self.actSelectAll)
733 mnuEdit.addAction(self.actSelectLine)
734 mnuEdit.addAction(self.actSelectWord)
735 mnuEdit.addSeparator()
736 mnuEdit.addAction(self.actDelete)
737 mnuEdit.addAction(self.actDeleteLine)
738 mnuEdit.addAction(self.actDeleteToStartLine)
739 mnuEdit.addAction(self.actDeleteToEndLine)
741 # Cards menu
742 mnuCards = self.menuBar().addMenu(tr("&Cards"))
743 mnuCards.addAction(self.actFirstCard)
744 mnuCards.addAction(self.actPreviousCard)
745 mnuCards.addAction(self.actNextCard)
746 mnuCards.addAction(self.actLastCard)
747 mnuCards.addSeparator()
748 mnuCards.addAction(self.actAddCard)
749 mnuCards.addAction(self.actInsertCard)
750 mnuCards.addAction(self.actDeleteCard)
751 mnuCards.addSeparator()
752 mnuCards.addAction(self.actSort)
753 mnuCards.addAction(self.actFilter)
754 mnuCards.addSeparator()
755 mnuCards.addAction(self.actNewItem)
756 mnuCards.addAction(self.actNewArticle)
757 mnuCards.addAction(self.actNewTask)
758 mnuCards.addSeparator()
759 actImportWeb = mnuCards.addAction(tr("Import &web pages"))
760 actImportWeb.setShortcut(QKeySequence("Shift+F8"))
761 mnuCards.addSeparator()
762 actAddToCategory = mnuCards.addAction(tr("Add &to category"))
763 actAddToReading = mnuCards.addAction(tr("Add to &reading list"))
764 actAddToTasklist = mnuCards.addAction(tr("Add to ta&sklist"))
765 mnuCards.addSeparator()
766 actCreateCategory = mnuCards.addAction(tr("Create &category"))
767 actCreateTasklist = mnuCards.addAction(tr("Create &tasklist"))
769 # Search menu
770 mnuSearch = self.menuBar().addMenu(tr("&Search"))
771 mnuSearch.addAction(self.actFindElements)
772 mnuSearch.addAction(self.actFindTexts)
773 mnuSearch.addAction(self.actFindWord)
774 mnuSearch.addAction(self.actFindString)
775 mnuSearch.addSeparator()
776 mnuSearch.addAction(self.actTextRegistry)
777 mnuSearch.addAction(self.actImages)
778 mnuSearch.addAction(self.actSounds)
779 mnuSearch.addSeparator()
780 mnuSearch.addAction(self.actTemplates)
781 mnuSearch.addAction(self.actCategories)
782 mnuSearch.addAction(self.actTasklists)
783 mnuSearchOtherReg = mnuSearch.addMenu(tr("&Other registries"))
784 mnuSearchOtherReg.addAction(self.actFont)
785 mnuSearchOtherReg.addSeparator()
786 mnuSearchOtherReg.addAction(self.actTranslation)
787 mnuSearchOtherReg.addAction(self.actPronunciationByWord)
788 mnuSearchOtherReg.addAction(self.actPronunciationBySound)
789 mnuSearchOtherReg.addAction(self.actComment)
790 mnuSearchOtherReg.addSeparator()
791 mnuSearchOtherReg.addAction(self.actVideo)
792 mnuSearchOtherReg.addAction(self.actScript)
793 mnuSearchOtherReg.addAction(self.actProgram)
794 mnuSearch.addSeparator()
795 mnuSearch.addAction(self.actGotoAncestor)
796 mnuSearch.addAction(self.actGotoElement)
799 # Learn menu
800 mnuLearn = self.menuBar().addMenu(tr("&Learn"))
801 mnuLearn.addAction(self.actLearnAllStages)
802 mnuLearnSelected = mnuLearn.addMenu(tr("&Selected stages"))
803 mnuLearnSelected.addAction(self.actLearnOutstanding)
804 mnuLearnSelected.addAction(self.actLearnNew)
805 mnuLearnSelected.addAction(self.actLearnFinalDrill)
806 mnuLearnSelected.addSeparator()
807 mnuLearnSelected.addAction(self.actReadingList)
808 mnuPostpone = mnuLearn.addMenu(tr("&Postpone"))
809 mnuPostpone.addAction(self.actPostponeTopics)
810 mnuPostpone.addAction(self.actPostponeItems)
811 mnuPostpone.addAction(self.actPostponeAll)
812 mnuLearn.addSeparator()
813 mnuRandom = mnuLearn.addMenu(tr("&Random"))
814 mnuRandom.addAction(self.actRandomizeRepetitions)
815 mnuRandom.addAction(self.actRandomLearning)
816 mnuLearn.addAction(self.actCutDrills)
818 # View menu
819 mnuView = self.menuBar().addMenu(tr("&View"))
820 mnuView.addAction(self.actAll)
821 mnuView.addAction(self.actOutstanding)
822 mnuView.addSeparator()
823 mnuView.addAction(self.actMemorized)
824 mnuView.addAction(self.actPending)
825 mnuView.addAction(self.actDismissed)
826 mnuView.addSeparator()
827 mnuView.addAction(self.actTopic)
828 mnuView.addAction(self.actItems)
829 mnuView.addAction(self.actTasks)
830 mnuView.addSeparator()
831 mnuView.addAction(self.actLastBrowser)
832 mnuView.addAction(self.actSearchResults)
833 mnuView.addAction(self.actSubset)
834 mnuView.addAction(self.actFilter)
835 mnuView.addSeparator()
836 mnuOtherBrowsers = mnuView.addMenu(tr("Other &browsers"))
837 mnuOtherBrowsers.addAction(self.actLeeches)
838 mnuOtherBrowsers.addAction(self.actSemiLeeches)
839 mnuOtherBrowsers.addAction(self.actDrill)
840 mnuOtherBrowsers.addAction(self.actRange)
841 mnuOtherBrowsers.addAction(self.actHistory)
842 mnuOtherBrowsers.addAction(self.actBranch)
845 # Tools mehu
846 mnuTools = self.menuBar().addMenu(tr("T&ools"))
847 mnuTools.addAction(self.actWorkload)
848 mnuTools.addAction(self.actPlan)
849 mnuTools.addAction(self.actMercy)
850 mnuTools.addAction(self.actTasklist)
851 mnuTools.addAction(self.actReadingList)
852 mnuStatistics = mnuTools.addMenu(tr("&Statistics"))
853 mnuStatistics.addAction(self.actStatistics)
854 mnuStatistics.addAction(self.actElementData)
855 mnuStatistics.addAction(self.actAnalysis)
856 mnuStatistics.addAction(self.actSimulation)
857 mnuStatistics.addAction(self.actReport)
858 mnuRandomize = mnuTools.addMenu(tr("&Randomize"))
859 mnuRandomize.addAction(self.actRandomizeDrill)
860 mnuRandomize.addAction(self.actRandomizePending)
861 mnuRandom = mnuTools.addMenu(tr("R&andom test"))
862 mnuRandom.addAction(self.actRandomTest)
863 mnuRandom.addSeparator()
864 mnuRandom.addAction(self.actRandomAll)
865 mnuRandom.addAction(self.actRandomPending)
866 mnuRandom.addAction(self.actRandomMemorized)
867 mnuRandom.addAction(self.actRandomDismissed)
868 mnuRandom.addSeparator()
869 mnuRandom.addAction(self.actRandomTopics)
870 mnuRandom.addAction(self.actRandomItems)
871 mnuRandom.addSeparator()
872 mnuRandom.addAction(self.actRandomFilter)
873 mnuRandom.addAction(self.actRandomLeeches)
874 mnuRandom.addSeparator()
875 mnuRandom.addAction(self.actRandomSubset)
876 mnuRandom.addSeparator()
877 mnuRandom.addAction(self.actRandomBranch)
878 mnuTools.addSeparator()
879 mnuTools.addAction(self.actOptions)
881 # Window menu
882 mnuWindow = self.menuBar().addMenu(tr("&Window"))
883 mnuWindow.addAction(self.actDock)
884 mnuToolbars = mnuWindow.addMenu(tr("&Toolbars"))
885 mnuToolbars.addAction(self.actToolbarRead)
886 mnuToolbars.addAction(self.actToolbarCompose)
887 mnuToolbars.addAction(self.actToolbarFormat)
888 mnuToolbars.addAction(self.actToolbarTime)
889 mnuToolbars.addAction(self.actToolbarActions)
890 mnuToolbars.addSeparator()
891 mnuToolbars.addAction(self.actDockToolbars)
892 mnuWindow.addAction(self.actStatusBar)
893 mnuWindow.addAction(self.actBackground)
894 mnuWindow.addAction(self.actHints)
895 mnuSelect = mnuWindow.addMenu(tr("S&elect"))
896 mnuSelect.addAction(self.actSelectCategory)
897 mnuSelect.addAction(self.actSelectTasklist)
898 mnuSelect.addAction(self.actSelectNextWindow)
899 mnuLayout = mnuWindow.addMenu(tr("&Layout"))
900 mnuLayout.addAction(self.actLayoutManager)
901 mnuLayout.addSeparator()
902 mnuLayout.addAction(self.actApplyDefaultLayout)
903 mnuLayout.addAction(self.actClassLayout)
904 mnuLayout.addSeparator()
905 mnuLayout.addAction(self.actSaveCustomLayout)
906 mnuLayout.addAction(self.actSaveAsDefault)
907 mnuLayout.addSeparator()
908 mnuLayout.addAction(self.actBackgroundColor)
909 mnuWindow.addSeparator()
910 mnuWindow.addAction(self.actLayoutLastUsed)
911 mnuWindow.addAction(self.actLayoutContents)
912 mnuWindow.addAction(self.actLayoutClassic)
913 mnuWindow.addAction(self.actLayoutBrowser)
916 # Help menu
917 mnuHelp = self.menuBar().addMenu(tr("&Help"))
918 mnuHelp.addAction(self.actWelcome)
919 mnuHelp.addAction(self.actGuide)
920 mnuHelp.addAction(self.actTroubleshooter)
921 mnuHelp.addAction(self.actFaq)
922 mnuHelp.addAction(self.actHintsAndTips)
923 mnuHelp.addAction(self.actContext)
924 mnuHelp.addSeparator()
925 mnuHelpWeb = mnuHelp.addMenu(tr("W&eb"))
926 mnuHelpWeb.addAction(self.actOnlineHelp)
927 mnuHelpWeb.addAction(self.actNews)
928 mnuHelpWeb.addAction(self.actWebFaq)
929 mnuHelpEmail = mnuHelp.addMenu(tr("E-&mail"))
930 mnuHelpEmail.addAction(self.actSupport)
931 mnuHelpEmail.addAction(self.actLibrary)
932 mnuHelpEmail.addSeparator()
933 mnuHelpEmail.addAction(self.actBugReport)
934 mnuHelpEmail.addAction(self.actQuestionnaire)
935 mnuHelpEmail.addAction(self.actRecommended)
936 mnuHelp.addSeparator()
937 mnuHelp.addAction(self.actQuestionOfDay)
938 mnuHelp.addSeparator()
939 mnuHelp.addAction(self.actAbout)
942 def createToolbars(self):
943 # File toolbar
944 tbFile = self.addToolBar(tr("File"))
945 tbFile.addAction(self.actAbout)
946 tbFile.addAction(self.actNewDeck)
947 tbFile.addAction(self.actExit)
948 tbFile.addAction(self.actNewItem)
949 tbFile.addAction(self.actNewArticle)
950 tbFile.addAction(self.actNewTask)
951 tbFile.addAction(self.actMemorized)
952 tbFile.addAction(self.actPending)
953 tbFile.addAction(self.actDismissed)
954 tbFile.addAction(self.actTasks)
955 tbFile.addAction(self.actLastBrowser)
956 tbFile.addAction(self.actSubset)
957 tbFile.addAction(self.actLeeches)
958 tbFile.setVisible(False)
960 # Other toolbar
961 tbView = self.addToolBar(tr("View"))
962 tbView.addAction(self.actLeeches)
963 tbView.addAction(self.actSemiLeeches)
964 tbView.addAction(self.actDrill)
965 tbView.addAction(self.actRange)
966 tbView.addAction(self.actHistory)
967 tbView.addAction(self.actBranch)
968 tbView.setVisible(False)
972 # recent file routines
973 # TODO is it the right way for these functions?
974 def getMostRecentFile(self):
975 """Returns most recently used file if valid."""
976 if len(config.GUI_RECENTFILES) > 0 and os.path.isfile(config.GUI_RECENTFILES[0]):
977 return config.GUI_RECENTFILES[0]
978 else:
979 return None
982 def removeRecentFile(self, fname):
983 """Removes given fname from recent files list"""
984 try:
985 config.GUI_RECENTFILES.remove(fname)
986 except:
987 pass
990 def addMostRecentFile(self, fname):
991 """Adds fname to most recently used files"""
992 # remove file if already on the list
993 try:
994 config.GUI_RECENTFILES.remove(fname)
995 except:
996 pass
997 # put it in front of all
998 config.GUI_RECENTFILES.insert(0, fname)
999 # trim to maximum number
1000 while len(config.GUI_RECENTFILES) > config.GUI_RECENTFILES_MAX:
1001 config.GUI_RECENTFILES = config.GUI_RECENTFILES[:-1]
1005 def createStatusBar(self):
1006 self.statusBar().showMessage(tr("Ready."))
1009 def _refreshAppState(self):
1010 """Sets control active or inactive depending on the database state."""
1011 # active/inactive actions
1012 # FIXME why are they not disabled/enabled ?
1013 self.actAddCard.setEnabled(self._cardModel.isActive())
1014 self.actDeleteCard.setEnabled(self._cardModel.isActive())
1015 self.actPreviousCard.setEnabled(self._cardModel.isActive())
1016 self.actNextCard.setEnabled(self._cardModel.isActive())
1017 # window title
1018 if self._cardModel.isActive():
1019 basename = os.path.basename(self._cardModel.filepath())
1020 self.setWindowTitle('Mentor - ' + os.path.splitext(basename)[0])
1021 else:
1022 self.setWindowTitle('Mentor')
1023 # recent files list
1024 for i in range(len(config.GUI_RECENTFILES)):
1025 self.actRecentFiles[i].setVisible(True)
1026 self.actRecentFiles[i].setText(config.GUI_RECENTFILES[i])
1027 self.actRecentFiles[i].setData(QVariant(config.GUI_RECENTFILES[i]))
1029 for i in range(len(config.GUI_RECENTFILES), config.GUI_RECENTFILES_MAX):
1030 self.actRecentFiles[i].setVisible(False)
1033 def _openDeckFile(self, fname):
1034 """Open deck with givem file name."""
1035 fname = str(fname)
1036 problem = False
1037 # FIXME running setCardModelIndex to empty
1038 # to clean all other views
1039 # I must redesign the model/view thing
1040 self.setCardModelIndex(QModelIndex())
1041 self.cardModel().close()
1042 try:
1043 self.cardModel().open(fname)
1044 self.setCardModelIndex(self.cardModel().index(0, 0))
1045 self.addMostRecentFile(fname)
1046 except:
1047 self.removeRecentFile(fname)
1048 self.setCardModelIndex(QModelIndex())
1049 problem = True
1050 finally:
1051 self._refreshAppState()
1052 if problem:
1053 show_info('Problem opening deck file %s.' % fname)
1056 def _newDeckFile(self, fname):
1057 """Creates a new deck with given file name."""
1058 fname = str(fname)
1059 problem = False
1060 # FIXME running setCardModelIndex with QModelIndex is HACK to clean
1061 # all other views - it must be run before closing cardModel
1062 # I must redesign the model/view thing
1063 self.setCardModelIndex(QModelIndex())
1064 self.cardModel().close()
1065 try:
1066 # we want to overwrite
1067 if os.path.isfile(fname):
1068 os.remove(fname)
1069 self.cardModel().open(fname)
1070 self.setCardModelIndex(self.cardModel().index(0, 0))
1071 self.addMostRecentFile(fname)
1072 except:
1073 config.remove_most_recent_file(fname)
1074 self.setCardModelIndex(QModelIndex())
1075 problem = True
1076 finally:
1077 self._refreshAppState()
1078 if problem:
1079 show_info('Problem creating a new deck file %s.' % fname)
1082 def _openRecentFile(self):
1083 if self.getMostRecentFile():
1084 self._openDeckFile(self.getMostRecentFile())
1085 self._refreshAppState()
1088 def qApp_aboutToQuit(self):
1089 if self.isMaximized():
1090 config.GUI_MAXIMIZED = True
1091 else:
1092 config.GUI_MAXIMIZED = False
1093 config.GUI_GEOMETRY = self.geometry()
1094 config.save()
1097 def on_actNewDeck_triggered(self):
1098 fileName = QFileDialog.getSaveFileName(self, \
1099 tr("New deck"), ".", tr("Mentor Card Deck files (*.mcd)"))
1100 if fileName:
1101 self._newDeckFile(fileName)
1105 def on_actOpenDeck_triggered(self):
1106 fname = QFileDialog.getOpenFileName(self, \
1107 tr("Open deck"), ".", tr("Mentor Card Deck files (*.mcd)"))
1108 if fname:
1109 self._openDeckFile(fname)
1111 def on_actCloseDeck_triggered(self):
1112 self.setCardModelIndex(QModelIndex())
1113 self.cardModel().close()
1114 self._refreshAppState()
1117 def on_actFirstCard_triggered(self):
1118 pass
1120 def on_actPreviousCard_triggered(self):
1121 """Moves current selection up by 1 row. If no selection is made then
1122 selects last item."""
1123 # move row up
1124 currentIndex = self.cardModelIndex()
1125 prevIndex = self._cardModel.getPreviousIndex(currentIndex)
1126 self.setCardModelIndex(prevIndex)
1128 def on_actNextCard_triggered(self):
1129 """Moves current selection down by 1 row. If no selection is made then
1130 selects first item."""
1131 currentIndex = self.cardModelIndex()
1132 nextIndex = self.cardModel().getNextIndex(currentIndex)
1133 self.setCardModelIndex(nextIndex)
1135 def on_actLastCard_triggered(self):
1136 pass
1138 def on_actAddCard_triggered(self):
1139 self.cardModel().addNewCard()
1140 # TODO what if it's not added at the end?
1141 newIndex = self.cardModel().index(self.cardModel().rowCount() - 1, 0)
1142 # go to newly added record
1143 self.setCardModelIndex(newIndex)
1146 def on_actInsertCard_triggered(self):
1147 pass
1149 def on_actDeleteCard_triggered(self):
1150 currentIndex = self.cardModelIndex()
1151 if currentIndex.isValid():
1152 # try to find currently selected row
1153 # and go to the same row
1154 # if rows are missing then go to last
1155 currentRow = currentIndex.row()
1156 self.cardModel().deleteCard(currentIndex)
1157 # go to new index
1158 newIndex = self.cardModel().index(min(currentRow, self.cardModel().rowCount() - 1), 0)
1159 self.setCardModelIndex(newIndex)
1162 def on_actAbout_triggered(self):
1163 show_info(tr("MENTOR version %s\nA learning tool\n\nDistributed under license: %s.\n\nAuthors: \n%s" \
1164 % (__version__, __license__, str(__author__))), self)
1166 def on_actCopyDeck_triggered(self):
1167 pass
1169 def on_actDeleteDeck_triggered(self):
1170 pass
1172 def on_actRepairDeck_triggered(self):
1173 pass
1175 def on_actMergeDeck_triggered(self):
1176 pass
1178 def on_actImportQA_triggered(self):
1179 # TODO must this have disabled if not database is open
1180 # TODO Option if want to clear existing or append
1181 fname = QFileDialog.getOpenFileName(self, \
1182 tr("Import Q&A file"), ".", tr("Q&A files (*.*)"))
1183 if fname:
1184 self.cardModel().importQAFile(str(fname))
1185 self.setCardModelIndex(self.cardModel().index(0, 0))
1186 self._refreshAppState()
1188 def on_actImportXML_triggered(self):
1189 pass
1191 def on_actImportProbe_triggered(self):
1192 pass
1194 def on_actImportProbe_triggered(self):
1195 pass
1197 def on_actExportQA_triggered(self):
1198 pass
1200 def on_actExportXML_triggered(self):
1201 pass
1203 def on_actExportProbe_triggered(self):
1204 pass
1206 def on_actExportProbe_triggered(self):
1207 pass
1209 def on_actExportProbe_triggered(self):
1210 pass
1213 def on_actOptions_triggered(self):
1214 dialog = OptionsDialog(self)
1215 dialog.setGeometry(200, 200, 600, 500)
1216 dialog.exec_()
1218 def on_actRecentFiles_triggered(self):
1219 self._openDeckFile(self.sender().text())
1221 def on_actFinalDrill_triggered(self):
1222 dialog = DrillWindow(self)
1224 # FIXME
1225 # load cards from model
1226 # should it work that way?
1227 # should model be more general (and have other operations?) or be
1228 # dedicated to browsing list only ?
1229 # maybe all operations should be done on the database level
1230 # and models only for browsing lists
1231 cards = []
1232 for row in range(self.cardModel().rowCount()):
1233 idx = self.cardModel().index(row, 0)
1234 card = self.cardModel().data(idx, Qt.UserRole)
1235 cards.append(card)
1237 dialog.loadCards(cards)
1239 dialog.exec_()
1241 def gridView_currentChanged(self, current, previous):
1242 self.setCardModelIndex(current)
1244 def gridView_activated(self, current):
1245 self.setCardModelIndex(current)
1248 def gridView_cardModelIndexChanged(self, current, previous):
1249 selection = self.gridView.selectionModel()
1250 selectedIndex = selection.selectedIndexes()
1251 if len(selectedIndex) > 0:
1252 selectedIndex = selectedIndex[0]
1253 else:
1254 selectedIndex = QModelIndex()
1255 # if is changed then update list view and card model
1256 if current != selectedIndex:
1257 selection.setCurrentIndex(current, QItemSelectionModel.SelectCurrent)
1263 def main():
1264 app = QApplication(sys.argv)
1265 # app.setStyle('cde')
1267 w = MainWindow()
1268 if config.GUI_LAZY_SHOW:
1269 lazyshow(w)
1270 else:
1271 w.show()
1273 app.exec_()
1275 if __name__ == "__main__":
1276 main()