| | 16 | from dabo.ui import dKeys |
|---|
| | 17 | |
|---|
| | 18 | |
|---|
| | 19 | class _LookupPanel(dabo.ui.dPanel): |
|---|
| | 20 | """Used for the command history search""" |
|---|
| | 21 | def afterInit(self): |
|---|
| | 22 | self._history = None |
|---|
| | 23 | self._displayedHistory = None |
|---|
| | 24 | self.currentSearch = "" |
|---|
| | 25 | self.needRefilter = False |
|---|
| | 26 | self.lblSearch = dabo.ui.dLabel(self) |
|---|
| | 27 | self.lstMatch = dabo.ui.dListBox(self, ValueMode="string", Choices=[], |
|---|
| | 28 | OnMouseLeftDoubleClick=self.selectCmd, OnKeyChar=self.onListKey) |
|---|
| | 29 | self.Sizer = dabo.ui.dSizer("v", DefaultBorder=4) |
|---|
| | 30 | self.Sizer.append(self.lblSearch, halign="center") |
|---|
| | 31 | self.Sizer.append(self.lstMatch, "x", 1) |
|---|
| | 32 | self.Width = 400 |
|---|
| | 33 | self.layout() |
|---|
| | 34 | |
|---|
| | 35 | |
|---|
| | 36 | def clear(self): |
|---|
| | 37 | """Reset to original state.""" |
|---|
| | 38 | self.ok = False |
|---|
| | 39 | self.currentSearch = self.lblSearch.Caption = "" |
|---|
| | 40 | self.refilter() |
|---|
| | 41 | |
|---|
| | 42 | |
|---|
| | 43 | def onListKey(self, evt): |
|---|
| | 44 | """Process keypresses in the command list control""" |
|---|
| | 45 | kc = evt.keyCode |
|---|
| | 46 | char = evt.keyChar |
|---|
| | 47 | if kc in (dKeys.key_Return, dKeys.key_Numpad_enter): |
|---|
| | 48 | self.closeDialog(True) |
|---|
| | 49 | return |
|---|
| | 50 | elif kc == dKeys.key_Escape: |
|---|
| | 51 | self.closeDialog(False) |
|---|
| | 52 | if kc in dKeys.arrows or char is None: |
|---|
| | 53 | #ignore |
|---|
| | 54 | return |
|---|
| | 55 | if kc == dKeys.key_Back: |
|---|
| | 56 | self.currentSearch = self.currentSearch[:-1] |
|---|
| | 57 | else: |
|---|
| | 58 | self.currentSearch += char |
|---|
| | 59 | self.lblSearch.Caption = self.currentSearch |
|---|
| | 60 | self.layout() |
|---|
| | 61 | self.needRefilter = True |
|---|
| | 62 | evt.stop() |
|---|
| | 63 | |
|---|
| | 64 | |
|---|
| | 65 | def closeDialog(self, ok): |
|---|
| | 66 | """Hide the dialog, and set the ok/cancel flag""" |
|---|
| | 67 | self.ok = ok |
|---|
| | 68 | self.Form.hide() |
|---|
| | 69 | |
|---|
| | 70 | |
|---|
| | 71 | def getCmd(self): |
|---|
| | 72 | return self.lstMatch.Value |
|---|
| | 73 | |
|---|
| | 74 | |
|---|
| | 75 | def selectCmd(self, evt): |
|---|
| | 76 | self.closeDialog(True) |
|---|
| | 77 | |
|---|
| | 78 | |
|---|
| | 79 | def onIdle(self, evt): |
|---|
| | 80 | """For performance, don't filter on every keypress. Wait until idle.""" |
|---|
| | 81 | if self.needRefilter: |
|---|
| | 82 | self.needRefilter = False |
|---|
| | 83 | self.refilter() |
|---|
| | 84 | |
|---|
| | 85 | |
|---|
| | 86 | def refilter(self): |
|---|
| | 87 | """Display only those commands that contain the search string""" |
|---|
| | 88 | self.DisplayedHistory = self.History.filter("cmd", self.currentSearch, "contains") |
|---|
| | 89 | sel = self.lstMatch.Value |
|---|
| | 90 | self.lstMatch.Choices = [rec["cmd"] for rec in self.DisplayedHistory] |
|---|
| | 91 | if sel: |
|---|
| | 92 | try: |
|---|
| | 93 | self.lstMatch.Value = sel |
|---|
| | 94 | except ValueError: |
|---|
| | 95 | self._selectFirst() |
|---|
| | 96 | else: |
|---|
| | 97 | self._selectFirst() |
|---|
| | 98 | |
|---|
| | 99 | |
|---|
| | 100 | def _selectFirst(self): |
|---|
| | 101 | """Select the first item in the list, if available.""" |
|---|
| | 102 | if len(self.lstMatch.Choices): |
|---|
| | 103 | self.lstMatch.PositionValue = 0 |
|---|
| | 104 | |
|---|
| | 105 | |
|---|
| | 106 | def _getHistory(self): |
|---|
| | 107 | if self._history is None: |
|---|
| | 108 | self._history = dabo.db.dDataSet() |
|---|
| | 109 | return self._history |
|---|
| | 110 | |
|---|
| | 111 | def _setHistory(self, val): |
|---|
| | 112 | if self._constructed(): |
|---|
| | 113 | self._history = self._displayedHistory = val |
|---|
| | 114 | try: |
|---|
| | 115 | self.lstMatch.Choices = [rec["cmd"] for rec in self.DisplayedHistory] |
|---|
| | 116 | self._selectFirst() |
|---|
| | 117 | except AttributeError: |
|---|
| | 118 | pass |
|---|
| | 119 | else: |
|---|
| | 120 | self._properties["History"] = val |
|---|
| | 121 | |
|---|
| | 122 | |
|---|
| | 123 | def _getDisplayedHistory(self): |
|---|
| | 124 | if self._displayedHistory is None: |
|---|
| | 125 | self._displayedHistory = self.History |
|---|
| | 126 | return self._displayedHistory |
|---|
| | 127 | |
|---|
| | 128 | def _setDisplayedHistory(self, val): |
|---|
| | 129 | if self._constructed(): |
|---|
| | 130 | self._displayedHistory = val |
|---|
| | 131 | else: |
|---|
| | 132 | self._properties["DisplayedHistory"] = val |
|---|
| | 133 | |
|---|
| | 134 | |
|---|
| | 135 | DisplayedHistory = property(_getDisplayedHistory, _setDisplayedHistory, None, |
|---|
| | 136 | _("Filtered copy of the History (dDataSet)")) |
|---|
| | 137 | |
|---|
| | 138 | History = property(_getHistory, _setHistory, None, |
|---|
| | 139 | _("Dataset containing the command history (dDataSet)")) |
|---|
| | 140 | |
|---|
| 43 | | # def processLine(self): |
|---|
| 44 | | # """This is a workaroundfor the fact that otherwise, the global _() function |
|---|
| 45 | | # will get replaced by the Python interpreter's default behavior of stuffing |
|---|
| 46 | | # the results of the last evaluation into the __builtin__ module's '_' attribute. |
|---|
| 47 | | # This results in all subsequent localization attempts failing, so after every line |
|---|
| 48 | | # that executes we re-assign the value to the one held in dabo.dLocalize. |
|---|
| 49 | | # """ |
|---|
| 50 | | # super(_Shell, self).processLine() |
|---|
| 51 | | # __builtin__._ = dabo.dLocalize._translationFunction |
|---|
| 52 | | |
|---|
| 53 | | |
|---|
| | 169 | def processLine(self): |
|---|
| | 170 | """This is part of the underlying class. We need to add the command that |
|---|
| | 171 | gets processed into our internal stack. |
|---|
| | 172 | """ |
|---|
| | 173 | edt = self.CanEdit() |
|---|
| | 174 | super(_Shell, self).processLine() |
|---|
| | 175 | if edt: |
|---|
| | 176 | # push the latest command into the stack |
|---|
| | 177 | self.Form.addToHistory(self.history[0]) |
|---|
| | 178 | |
|---|
| | 179 | |
|---|
| | 373 | def addToHistory(self, cmd): |
|---|
| | 374 | if cmd == self._lastCmd: |
|---|
| | 375 | # Don't add again |
|---|
| | 376 | return |
|---|
| | 377 | self._lastCmd = cmd |
|---|
| | 378 | stamp = "%s" % int(round(time.time() * 100, 0)) |
|---|
| | 379 | self.cmdHistKey.setValue(stamp, cmd) |
|---|
| | 380 | |
|---|
| | 381 | |
|---|
| | 382 | def onShellKeyDown(self, evt): |
|---|
| | 383 | if evt.controlDown and evt.keyChar in ("r", "R"): |
|---|
| | 384 | if not (evt.commandDown or evt.altDown or evt.metaDown): |
|---|
| | 385 | evt.stop() |
|---|
| | 386 | self.historyPop() |
|---|
| | 387 | |
|---|
| | 388 | |
|---|
| | 389 | def _loadHistory(self): |
|---|
| | 390 | ck = self.cmdHistKey |
|---|
| | 391 | cmds = [] |
|---|
| | 392 | for k in ck.getPrefKeys(): |
|---|
| | 393 | cmds.append({"stamp": k, "cmd": ck.get(k)}) |
|---|
| | 394 | dsu = dabo.db.dDataSet(cmds) |
|---|
| | 395 | ds = dsu.sort("stamp", "desc") |
|---|
| | 396 | return ds |
|---|
| | 397 | |
|---|
| | 398 | |
|---|
| | 399 | def historyPop(self): |
|---|
| | 400 | """Let the user type in part of a command, and retrieve the matching commands |
|---|
| | 401 | from their history. |
|---|
| | 402 | """ |
|---|
| | 403 | ds = self._loadHistory() |
|---|
| | 404 | hp = self._HistoryPanel |
|---|
| | 405 | hp.History = ds |
|---|
| | 406 | fp = self.FloatingPanel |
|---|
| | 407 | # We want it centered, so set Owner to None |
|---|
| | 408 | fp.Owner = None |
|---|
| | 409 | hp.clear() |
|---|
| | 410 | fp.show() |
|---|
| | 411 | if hp.ok: |
|---|
| | 412 | cmd = hp.getCmd() |
|---|
| | 413 | if cmd: |
|---|
| | 414 | pos = self.shell.history.index(cmd) |
|---|
| | 415 | self.shell.replaceFromHistory(pos - self.shell.historyIndex) |
|---|
| | 416 | |
|---|
| | 417 | |
|---|
| | 418 | def restoreHistory(self): |
|---|
| | 419 | """Get the stored history from previous sessions, and set the shell's |
|---|
| | 420 | internal command history list to it. |
|---|
| | 421 | """ |
|---|
| | 422 | ds = self._loadHistory() |
|---|
| | 423 | self.shell.history = [rec["cmd"] for rec in ds] |
|---|
| | 424 | |
|---|
| | 425 | |
|---|
| | 426 | def _clearOldHistory(self): |
|---|
| | 427 | """For performance reasons, only save up to 500 commands.""" |
|---|
| | 428 | numToSave = 500 |
|---|
| | 429 | ck = self.cmdHistKey |
|---|
| | 430 | ds = self._loadHistory() |
|---|
| | 431 | if len(ds) <= numToSave: |
|---|
| | 432 | return |
|---|
| | 433 | cutoff = ds[numToSave]["stamp"] |
|---|
| | 434 | bad = [] |
|---|
| | 435 | for rec in ds: |
|---|
| | 436 | if rec["stamp"] <= cutoff: |
|---|
| | 437 | bad.append(rec["stamp"]) |
|---|
| | 438 | for bs in bad: |
|---|
| | 439 | ck.deletePref(bs) |
|---|
| | 440 | |
|---|
| | 441 | |
|---|
| | 511 | def _getFontSize(self): |
|---|
| | 512 | return self.shell.FontSize |
|---|
| | 513 | |
|---|
| | 514 | def _setFontSize(self, val): |
|---|
| | 515 | if self._constructed(): |
|---|
| | 516 | self.shell.FontSize = val |
|---|
| | 517 | else: |
|---|
| | 518 | self._properties["FontSize"] = val |
|---|
| | 519 | |
|---|
| | 520 | |
|---|
| | 521 | def _getFontFace(self): |
|---|
| | 522 | return self.shell.FontFace |
|---|
| | 523 | |
|---|
| | 524 | def _setFontFace(self, val): |
|---|
| | 525 | if self._constructed(): |
|---|
| | 526 | self.shell.FontFace = val |
|---|
| | 527 | else: |
|---|
| | 528 | self._properties["FontFace"] = val |
|---|
| | 529 | |
|---|
| | 530 | |
|---|
| | 531 | def _getHistoryPanel(self): |
|---|
| | 532 | fp = self.FloatingPanel |
|---|
| | 533 | try: |
|---|
| | 534 | create = self._historyPanel is None |
|---|
| | 535 | except AttributeError: |
|---|
| | 536 | create = True |
|---|
| | 537 | if create: |
|---|
| | 538 | fp.clear() |
|---|
| | 539 | pnl = self._historyPanel = _LookupPanel(fp) |
|---|
| | 540 | pnl.Height = max(200, self.Height-100) |
|---|
| | 541 | fp.Sizer.append(pnl) |
|---|
| | 542 | fp.fitToSizer() |
|---|
| | 543 | return self._historyPanel |
|---|
| | 544 | |
|---|
| | 545 | |
|---|