1 from builtins
import range
13 """ Base class for all tab controllers. 15 Tab controllers control the functionality of plugin tabs. 18 TAB_LABEL_MAX_LENGTH = 20
21 QObject.__init__(self)
22 logging.debug(__name__ +
": __init__")
41 """ Static function returning all filetypes the tab controller can handle. 43 Sub classes should reimplement this function. It returns a list with 2-tuples of the following form: 44 ('extension', 'description of file type'). 47 staticSupportedFileTypes = staticmethod(staticSupportedFileTypes)
50 """ Returns staticSupportedFileTypes() of the class to which this object belongs. 52 return self.__class__.staticSupportedFileTypes()
55 supportedFileTypes = self.__class__.staticSupportedFileTypes()
56 return ";;".
join([
Filetype(t[0], t[1]).fileDialogFilter()
for t
in supportedFileTypes])
59 """ Returns the plugin reference, set by setPlugin(). 81 """ Returns filename of this tab. 86 """ Returns the basename of this tab's filename. 88 Part of filename after last /. 93 """ Sets a flag indicating whether this tab can handle copy and paste events. 95 See also isCopyPasteEnabled(), cut(), copy(), paste(). 100 """ Return True if the copyPasteFlag is set. 102 See setCopyPasteEnabled(), cut(), copy(), paste(). 107 """Sets a flag indicating whether this tab can handle find requests. 109 See isFindEnabled(), find(). 114 """Returns True if findEnabledFlag is set. 116 See setFindEnabled(), find(). 121 """ Sets the text of the tab to filename if it is set. If 123 is not an emty string, it is used instead of the filename. 125 Otherwise it is set to 'UNTITLED'. It also evaluates the fileModifiedFlag and indicates changes with an *. 129 if len(os.path.splitext(title)[0]) > self.TAB_LABEL_MAX_LENGTH:
130 ext = os.path.splitext(title)[1].lower().
strip(
".")
131 title = os.path.splitext(title)[0][0:self.TAB_LABEL_MAX_LENGTH] +
"...." + ext
132 elif titletext ==
"":
142 if self.
tab().tabWidget():
143 self.
tab().tabWidget().setTabText(self.
tab().tabWidget().indexOf(self.
tab()), title)
145 self.
tab().setWindowTitle(title)
148 """ Sets the file Modified flag to True or False. 150 This affects the closing of this tab. 151 It is only possible to set the modification flag to True if the controller is editable (see isEditable()). 161 if self.
tab().mainWindow():
162 self.
plugin().application().updateMenuAndWindowTitle()
164 logging.info(self.__class__.__name__ +
": setModified() - Cannot tell application the modification state: There is no application associated with the tab.")
167 """ Evaluates the file Modified flag. Always returns True if no filename is set. 172 """ Sets the file Editable flag. 176 self.
plugin().application().updateMenu()
179 """ Evaluates the file Editable flag. 184 """ Sets the allowSelectAll flag. 187 self.
plugin().application().updateMenu()
190 """ Evaluates the sllowSelectAll flag. 194 def open(self, filename=None, update=True):
197 logging.debug(self.__class__.__name__ +
": open()")
199 statusMessage = self.
plugin().application().startWorking(
"Opening file " + filename)
205 self.
plugin().application().stopWorking(statusMessage,
"failed")
213 self.
plugin().application().stopWorking(statusMessage)
216 self.
plugin().application().stopWorking(statusMessage,
"failed")
221 This function performs the actual reading of a file. It should be overwritten by any PluginTab which inherits Tab. 222 If the reading was successful True should be returned. 223 The file should be read from the file given in the argument filename not to the one in self._filename. 225 raise NotImplementedError
228 """ Takes care the tab's data will be written to the file given as argument or if this is an empty string to self._filename. 230 Whenever the content of the tab should be saved, this method should be called. If no filename is specified nor already set set it asks the user to set one. 231 Afterwards the writing is initiated by calling writeFile(). 239 return self.
plugin().application().saveFileAsDialog()
241 statusMessage = self.
plugin().application().startWorking(
"Saving file " + filename)
247 except Exception
as e:
254 self.
plugin().application().addRecentFile(filename)
255 self.
plugin().application().updateMenuAndWindowTitle()
261 lastSavedStateEvent =
None 264 self.
plugin().application().stopWorking(statusMessage)
267 QMessageBox.critical(self.
tab().mainWindow(),
'Error while saving data',
'Could not write to file ' + filename +
'.'+message)
268 logging.error(self.__class__.__name__ +
": save() : Could not write to file " + filename +
'.'+message)
269 self.
plugin().application().stopWorking(statusMessage,
"failed")
274 messageResult = self.
plugin().application().showMessageBox(
"The document has been modified.",
275 "Do you want to save your changes?",
276 QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel,
279 if messageResult == QMessageBox.Save:
282 elif messageResult == QMessageBox.Cancel:
287 """ Asks user if he wants to save potentially unsaved data and closes the tab. 289 This function usually does not need to be overwritten by a PluginTab. 293 if self.
tab().tabWidget():
294 self.
tab().tabWidget().removeTab(self.
tab().tabWidget().indexOf(self.
tab()))
305 This function performs the actual writing / saving of a file. It should be overwritten by any PluginTab which inherits Tab. 306 If the writing was successful True should be returned. 307 The file should be written to the file given in the argument filename not to the one in self._filename. 308 These variables may differ in case the user selects "save as..." and picks a new filename on a file which already has a name set. 309 If writing was successful the self._filename variable will then be set to the value of filename. 311 raise NotImplementedError
314 """ Compares the actual modification timestamp of self.filename() to the modification at opening or last save operation. 316 This function is called by Application when the tab associated with this controller was activated. 317 If modification timestamps differ the refresh() method is called. 324 logging.debug(self.__class__.__name__ +
": checkModificationTimestamp() - File was removed.")
326 msgBox = QMessageBox()
327 msgBox.setText(
"The file was removed.")
329 msgBox.setInformativeText(
"Do you want to save the file with your version?")
330 saveButton = msgBox.addButton(
"Save", QMessageBox.ActionRole)
331 ignoreButton = msgBox.addButton(
"Ignore", QMessageBox.RejectRole)
333 ignoreButton = msgBox.addButton(
"OK", QMessageBox.RejectRole)
337 logging.debug(self.__class__.__name__ +
": checkModificationTimestamp() - File was modified.")
338 msgBox = QMessageBox()
339 msgBox.setText(
"The file has been modified.")
341 msgBox.setInformativeText(
"Do you want to overwrite the file with your version or reload the file?")
342 saveButton = msgBox.addButton(
"Overwrite", QMessageBox.ActionRole)
344 msgBox.setInformativeText(
"Do you want to reload the file?")
345 reloadButton = msgBox.addButton(
"Reload", QMessageBox.DestructiveRole)
346 ignoreButton = msgBox.addButton(
"Ignore", QMessageBox.RejectRole)
354 if self.
isEditable()
and msgBox.clickedButton() == saveButton:
356 elif msgBox.clickedButton() == reloadButton:
359 elif msgBox.clickedButton() == ignoreButton
and os.path.exists(self.
_filename):
367 """ Called by application when tab is activated in tabWidget. 369 This function should be overwritten if special treatment on tab selection is required. 374 """ Handle cut event. 376 This function is called if the user selects 'Cut' from menu. PluginTabs should override it if needed. 377 See also setCopyPasteEnabled(), isCopyPasteEnabled(). 379 raise NotImplementedError
382 """ Handle copy event. 384 This function is called if the user selects 'Copy' from menu. PluginTabs should override it if needed. 385 See also setCopyPasteEnabled(), isCopyPasteEnabled(). 387 raise NotImplementedError
390 """ Handle paste event. 392 This function is called if the user selects 'Paste' from menu. PluginTabs should override it if needed." 393 See also setCopyPasteEnabled(), isCopyPasteEnabled(). 395 raise NotImplementedError
398 """ Handle find event. 400 This function is called if the user selects 'Find' from menu. PluginTabs should override it if needed." 401 See also setFindEnabled(), isFindEnabled(). 403 raise NotImplementedError
406 """ Handle to perform select all action. 408 This function is called if the user selects 'Select all' from menu. PluginTabs should override it if needed." 409 See also setAllowSelectAll(), allowSelectAll(). 411 raise NotImplementedError
414 """ This function has to be implemented by tab controllers who want to use the zoom toolbar. 416 The implementation has to forward the zoom value to the Zoomable object for which the toolbar is set up. 419 raise NotImplementedError
422 """ This function has to be implemented by tab controllers who want to use the zoom toolbar. 424 The implementation should return the zoom value of the Zoomable object for which the toolbar is set up. 427 raise NotImplementedError
430 """ Shows zoom value on main window's status bar. 432 self.
tab().mainWindow().statusBar().showMessage(
"Zoom " +
str(round(zoom)) +
" %")
435 """ Sets the zoom button pressed before flag to False. 437 If the flag is set functions handling the zoom toolbar buttons (zoomHundred(), zoomAll()) wont store the last zoom factor. The flag is set to true by these functions. 438 By this mechanism the user can click the zoom buttons several times and will still be able to return to his orignal zoom level by zoomUser(). 439 The reset function needs to be called if the user manually sets the zoom level. For instance by connecting this function to the wheelEvent of the workspace scroll area. 444 """ Returns to the manually set zoom factor before zoomHundred() or zoomAll() were called. 446 logging.debug(__name__ +
": zoomUser()")
450 """ Sets zoom factor to 100 %. 452 logging.debug(__name__ +
": zoomHundred()")
459 """ Zooms workspace content to fit optimal. 461 Currently only works if scroll area is used and accessible through self.tab().scrollArea(). 463 logging.debug(__name__ +
": zoomAll()")
468 viewportWidth = self.
tab().scrollArea().viewport().
width()
469 viewportHeight = self.
tab().scrollArea().viewport().height()
471 for i
in range(0, 2):
473 workspaceChildrenRect = self.
tab().scrollArea().widget().childrenRect()
474 widthRatio = self.
zoom() * viewportWidth / (workspaceChildrenRect.right())
475 heightRatio = self.
zoom() * viewportHeight / (workspaceChildrenRect.bottom())
477 if widthRatio > heightRatio:
482 self.
setZoom(math.floor(ratio))
485 """ Called after file is loaded. 487 Meant to update to Tab content. 489 raise NotImplementedError
492 """ Reloads file content and refreshes tab. 494 May be implemented by inheriting controllers. 496 statusMessage = self.
plugin().application().startWorking(
"Reopening file")
500 self.
plugin().application().stopWorking(statusMessage)
503 if hasattr(QInputDialog,
"getInteger"):
505 (zoom, ok) = QInputDialog.getInteger(self.
tab(),
"Zoom...",
"Input zoom factor in percent:", self.
zoom(), 0)
508 (zoom, ok) = QInputDialog.getInt(self.
tab(),
"Zoom...",
"Input zoom factor in percent:", self.
zoom(), 0)
514 """ Cancel all operations in tab. 516 This function is called when all current operations in tab shall be canceled. 521 """ Returns True if the this tab controller supports undo history. 523 return self._supportsUndo
526 """ If enable is True this controller enables its undo function. 528 For any tab controller that wants to use this feature, it needs to be made sure the corresponding UndoEvents 529 for actions that should be undoable exists and are added by addUndoEvent(). 534 """ Returns list of all registered UndoEvents. 539 """ Returns list of all UndoEvents that have already been undone before. 544 """ Adds event of type UndoEvent to this tab controller's list of undoable events. 546 Undo can be invoked by calling undo(). 549 if not isinstance(undoEvent, UndoEvent):
550 logging.error(
"%s: Tried to add non-UndoEvent to list of undo events. Aborting..." % self.__class__.__name__)
556 self._undoEvents.append(undoEvent)
559 self.
plugin().application().updateMenu()
561 logging.warning(
"%s: Tried to add undo event, however undo functionality is not enabled. Aborting..." % self.__class__.__name__)
564 def undo(self, numberOfEvents=1):
565 """ Invokes undo of last stored UndoEvent (see addUndoEvent()), if undo functionality is enabled. 568 logging.warning(self.__class__.__name__ +
": Tried to undo action, however undo functionality is not enabled. Aborting...")
570 logging.debug(self.__class__.__name__ +
": undo("+
str(numberOfEvents) +
")")
573 for i
in range(0, numberOfEvents):
575 lastEvent = self._undoEvents.pop()
577 self._redoEvents.append(lastEvent)
580 if i == (numberOfEvents -1):
581 if lastEvent.isLastSavedState():
585 self.
plugin().application().updateMenu()
589 def redo(self, numberOfEvents=1):
591 logging.warning(self.__class__.__name__ +
": Tried to undo action, however undo functionality is not enabled. Aborting...")
593 logging.debug(self.__class__.__name__ +
": redo("+
str(numberOfEvents) +
")")
596 for i
in range(0, numberOfEvents):
598 lastEvent = self._redoEvents.pop()
600 self._undoEvents.append(lastEvent)
603 if i == (numberOfEvents -1):
605 if undo_events_count > 0:
606 if self.
_redoEvents[undo_events_count-1].isLastSavedState():
617 if event.isLastSavedState():
621 self.
plugin().application().updateMenu()
624 """ Sets last saved state flag of given UndoEvent to True and to False for all other events. 627 if current_event == undoEvent:
628 current_event.setLastSavedState(
True)
630 current_event.setLastSavedState(
False)
def readFile(self, filename)
_showingModifiedMessageFlag
def setFindEnabled(self, enable=True)
def addUndoEvent(self, undoEvent)
def zoomChanged(self, zoom)
def setModified(self, modified=True)
def supportedFileFilters(self)
def getFileBasename(self)
def open(self, filename=None, update=True)
def undo(self, numberOfEvents=1)
def staticSupportedFileTypes()
_zoomButtonPressedBeforeFlag
def resetZoomButtonPressedBefore(self)
def isCopyPasteEnabled(self)
def setCopyPasteEnabled(self, enable=True)
def setFilename(self, filename)
def enableUndo(self, enable=True)
def setEditable(self, editable)
static std::string join(char **cmd)
def writeFile(self, filename)
def save(self, filename="")
def __init__(self, plugin)
def redo(self, numberOfEvents=1)
def checkModificationTimestamp(self)
def setLastSavedStateEvent(self, undoEvent)
_fileModifcationTimestamp
def supportedFileTypes(self)
def updateLabel(self, prefix="", titletext="")
def setAllowSelectAll(self, allowSelectAll)