diff python/apps/diagrameditor.py @ 81:49161141d765

Added icons and improved stability
author windel
date Fri, 16 Nov 2012 12:10:34 +0100
parents d1925eb3bbd5
children a47f6fec5435
line wrap: on
line diff
--- a/python/apps/diagrameditor.py	Wed Nov 14 18:09:32 2012 +0100
+++ b/python/apps/diagrameditor.py	Fri Nov 16 12:10:34 2012 +0100
@@ -2,7 +2,7 @@
 
 from PyQt4.QtGui import *
 from PyQt4.QtCore import *
-import sys, json
+import sys, json, base64
 
 """
  Author: Windel Bouwman
@@ -11,6 +11,11 @@
  run with python 3.x as:
   $ python [thisfile.py]
 """
+saveicon = b'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\nveAfetNmUUsM6bsAAAAASUVORK5CYII=\n'
+
+loadicon = b'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACsElEQVR42u2Xf0hTURTHv++ZczlD\n6SeUREVRiRT9gFWM1rbAwr+iYAathPqjMosIQQqJQAhLLDI0CMwflRa1vyQst0oNLKxhCGWR9UfB\nwFCRaqC2vc6d7+1tr/7YnuwW5IEv95y79875vHvP7t4E/GUTpgGmAaL8vaRzpDlx3iuRXpEOkz5N\nFWDhrHR8bL+LtGXLKUqRJcoKyeUk1Q8Fges3gLIKeGlm+1QBHA4rPJ7WxG4eHqLlWoJRcvfJaPHY\nV1LPbwB5Dnja7if+BFUVQEdX7OqETdL48vD+C/DODze5e9iUCmAjgDt6FzJ+m/gG5GyD9OEz1lPY\nqwLQFrQ1JR+Amc0JPO0O941XBbAQQB0nABcBvNACbCGAWk4ABwngpRbATACXEksU7rsJGlnzUSZB\nkEdAbW9lXgnJtx0jAJ8WYCMBnE8MIESFx7+rRQRRLiaPESANmL2EAF6jgaLSCIA9Bx53sZokJpEY\nm4zFzP85BgTn0mUZUL9y7CPpz8CCvAJdA0DrE6D6NnxsLp9UaV2KVfW7Jy8QWcGUyUJhP0piFJA0\nmw6iAn19EAgAmdkICpRw5EEdsjabgXQDYo9gRZENVxVeIJO8Gjqs7y2wxoJ+IXUGxkcHkDrTqC+R\nXrt5D3AVoYU9yJs+L1bnruQLUFJO+34NpxlAc2MVCly7+ALkHQAedSKfAZwq3o/KK2X8ikvUT4ss\nkPyDWMwAtm5ai47uZn4Ag8PAAgvoxxzzGUCGMQ1DI89gMBr4ADymtwHHIXSSa1UOIt/zBqwz5/IB\nqG4Bjl9EDblFCkDN5ZM4csLJB+DoBaDWDTp3cVUBcDntaLx1hg/AzlKgvQc7yH2oAGSbjOg/WwjT\nvMzkFvdT65U34UdgDCtYGP1avoFUSMpK8gKw7q8n9bLgn/pj8n8C/ALihrxpNKi7hQAAAABJRU5E\nrkJggg==\n'
+
+newicon = b'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADSUlEQVR42r2XO0xaURjHLzYmdXRi\nYXBwdDScJl3djQNLw0TSAR88FR9JU6P4QKMCaTqQdGgXsQQMQXFwcGXhCCG+4iNEo6mDMZL45kK/\n76THUO+9Qi/efskJcm4O3+/+v8f51Al/LBaLmTs6Or43gAkq7eHhoXh2dmZva2v7WusZHf9jZGTE\nPz4+blfjuFwuC6IoCsViUbi8vCwDhM1oNH75V4AAANjUAJRKJeYc183NjXB1dVU+Pj7+CIp+qxlg\neHg44PV6VQHg2z8+PjKAu7s7oampSQAVxL29PUtnZ+eP/waA6/r6WtDr9UyJ09NTcXd319LV1aUI\n8QQwNDQUmJiYqBsA5BcMBgPLC4Q4OTkRt7e3LSaTSRbiCWBwcDAwOTmpOgfQOVSBcHFxIbS0tLB9\nDgH5IGYyGYvZbJZAvAoAOsL4IwTEngGxH9fp2MJnhUJBTKfT5t7e3rAsgMfjYQB4oB4V+OJAuI+A\naGtra6nz8/P3o6OjJQnAwMBAYGpqSjUAh8Aw8JLE3OBqIMTGxgbNZrPE5/MVFQFUe6+A4M5xoWMe\nIg4ASksB+vv761aAG3eKMFwBBFhfX6ebm5sEyl0eAHOgjqvgRSBUA3KAghHouFIAt9vNFNACgIci\nmUxSKEcyNjYmBXC5XK8Wgudvz8OAAJgDigD1lGE155UAsiFwOp2vUgVKzisBZJMQAdR2wlqco62s\nrNBcLkfgzpECOByOuhXg5cc733NLJBIMQLYP2O12BqB0uJrjyk8li8fjdGtri4AfeQAMAUpXayJW\ne2MlANlWbLPZGAB2LPagCoQapZaXl+nOzg6ZmZmRB8CBhANoYTB5U5iQyOzsrDwAjmR4hWpl0WiU\nwpxI5ubmpAAwKLAQ4HWqlUUiEbq/v0/m5+flATAEWiqwtLREDw4OyMLCgjyA1iEIh8P08PCQ+P1+\nKUBPTw8D0DIEi4uL9OjoiASDQSlAd3c3A7i/v9cUAKsgFApJAaxWa2B6etp2e3v71yGlen++X60v\n4EwAAOlUKvUO+oEUoLW19UNfX9/nxsbGhsoOxy+Wl75X2+drdXX1J/zX9AkmI+lU3N7e/hYSxAAT\n0Rs+FdX69rXsA1y5ubn5Vz6fL1Q++w30VO4/0/9IewAAAABJRU5ErkJggg==\n'
 
 def buildPath(pts):
    path = QPainterPath(pts[0])
@@ -314,17 +319,24 @@
    def getModel(self): return self._model
    def setModel(self, m):
       self._model = m
-      self.treeView.setModel(m)
-      self.diagram = m.rootDiagram
+      if m:
+         self.treeView.setModel(m)
+         self.diagram = m.rootDiagram
    model = property(getModel, setModel)
    diagram = property(lambda s: s.scene(), setDiagram)
    def save(self):
-      filename = 'diagram4.usd'
-      with open(filename, 'w') as f:
-         f.write(json.dumps(self.model.Dict))
+      if self.model:
+         if not self.model.filename:
+            self.model.filename = QFileDialog.getSaveFileName(self)
+         if self.model.filename:
+            with open(self.model.filename, 'w') as f:
+               f.write(json.dumps(self.model.Dict))
    def load(self):
       filename = QFileDialog.getOpenFileName(self)
-      self.model = loadModel(filename)
+      if filename:
+         self.model = loadModel(filename)
+   def newModel(self):
+      self.model = ModelHierarchyModel()
    def goUp(self):
       if hasattr(self.diagram, 'containingBlock'):
          self.diagram = self.diagram.containingBlock.scene()
@@ -366,6 +378,7 @@
    def __init__(self):
       super(ModelHierarchyModel, self).__init__()
       self.rootDiagram = DiagramScene()
+      self.filename = None
    def setDict(self, d):
       self.rootDiagram.Dict = d
       self.modelReset.emit()
@@ -481,13 +494,22 @@
       self.setViewMode(self.IconMode)
       self.setDragDropMode(self.DragOnly)
 
+def warning(txt):
+   QMessageBox.warning(None, "Warning", txt)
+
 def loadModel(filename):
-   m = ModelHierarchyModel()
    try:
+      m = ModelHierarchyModel()
       with open(filename, 'r') as f: data = f.read()
+      m.filename = filename
       m.Dict = json.loads(data)
-   except FileNotFoundError: pass
-   return m
+      return m
+   except KeyError:
+      warning('Corrupt model: {0}'.format(filename))
+   except ValueError:
+      warning('Corrupt model: {0}'.format(filename))
+   except FileNotFoundError:
+      warning('File [{0}] not found'.format(filename))
 
 class Main(QMainWindow):
    def __init__(self):
@@ -495,26 +517,53 @@
       self.editor = EditorGraphicsView()
       self.setCentralWidget(self.editor)
       self.setWindowTitle("Diagram editor")
+      def buildIcon(b64):
+         icon = base64.decodestring(b64)
+         pm = QPixmap()
+         pm.loadFromData(icon)
+         return QIcon(pm)
       toolbar = self.addToolBar('Tools')
-      def act(name, shortcut, callback):
-         a = QAction(name, self)
+      toolbar.setObjectName('Tools')
+      def act(name, shortcut, callback, icon=None):
+         a = QAction(icon, name, self) if icon else QAction(name, self)
          a.setShortcuts(shortcut)
          a.triggered.connect(callback)
          toolbar.addAction(a)
-      act('Save', QKeySequence.Save, self.editor.save)
-      act('Load', QKeySequence.Open, self.editor.load)
+      act('New', QKeySequence.New, self.editor.newModel, buildIcon(newicon))
+      act('Save', QKeySequence.Save, self.editor.save, buildIcon(saveicon))
+      act('Load', QKeySequence.Open, self.editor.load, buildIcon(loadicon))
       act('Full screen', QKeySequence("F11"), self.toggleFullScreen)
       act('Fit in view', QKeySequence("F8"), self.editor.zoomAll)
       act('Go up', QKeySequence(Qt.Key_Up), self.editor.goUp)
       def addDock(name, widget):
          dock = QDockWidget(name, self)
+         dock.setObjectName(name)
          dock.setWidget(widget)
          self.addDockWidget(Qt.LeftDockWidgetArea, dock)
       addDock('Library', LibraryWidget())
       addDock('Model tree', self.editor.treeView)
+      self.settings = QSettings('windelsoft', 'diagrameditor')
+      self.loadSettings()
    def toggleFullScreen(self):
       self.setWindowState(self.windowState() ^ Qt.WindowFullScreen)
       self.editor.zoomAll()
+   def loadSettings(self):
+      if self.settings.contains('mainwindowstate'):
+         self.restoreState(self.settings.value('mainwindowstate'))
+      if self.settings.contains('mainwindowgeometry'):
+         self.restoreGeometry(self.settings.value('mainwindowgeometry'))
+      if self.settings.contains('openedmodel'):
+         modelfile = self.settings.value('openedmodel')
+         self.editor.model = loadModel(modelfile)
+   def closeEvent(self, ev):
+      self.settings.setValue('mainwindowstate', self.saveState())
+      self.settings.setValue('mainwindowgeometry', self.saveGeometry())
+      if self.editor.model and self.editor.model.filename:
+         self.settings.setValue('openedmodel', self.editor.model.filename)
+         # TODO: ask for save of opened files
+      else:
+         self.settings.remove('openedmodel')
+      ev.accept()
 
 if __name__ == '__main__':
    if sys.version_info.major != 3:
@@ -523,7 +572,5 @@
    app = QApplication(sys.argv)
    main = Main()
    main.show()
-   main.resize(700, 500)
-   main.editor.model = loadModel('diagram4.usd')
    app.exec_()