Example #1
0
class Window(QMainWindow):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.image = QImage()
        self.dirty = False
        self.filename = None
        self.mirroredvertically = False
        self.mirroredhorizontally = False
        self.printer = None
        self.create_widgets()
        self.create_actions()
        self.load_settings()
        self.setWindowTitle("Image Changer")
        self.updateFileMenu()
        QTimer.singleShot(0, self.loadInitialFile)

    def create_widgets(self):
        self.imageLabel = QLabel()
        self.imageLabel.setMinimumSize(200, 200)
        self.imageLabel.setAlignment(Qt.AlignCenter)
        self.imageLabel.setContextMenuPolicy(Qt.ActionsContextMenu)
        self.setCentralWidget(self.imageLabel)

        logDockWidget = QDockWidget("Log", self)
        logDockWidget.setObjectName("LogDockWidget")
        logDockWidget.setAllowedAreas(Qt.LeftDockWidgetArea
                                      | Qt.RightDockWidgetArea)
        self.listWidget = QListWidget()
        logDockWidget.setWidget(self.listWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, logDockWidget)

        self.sizeLabel = QLabel()
        self.sizeLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        status = self.statusBar()
        status.setSizeGripEnabled(False)
        status.addPermanentWidget(self.sizeLabel)
        status.showMessage("Ready", 5000)

    def create_actions(self):
        fileNewAction = self.createAction("&New...", self.fileNew,
                                          QKeySequence.New, "filenew",
                                          "Create an image file")
        fileOpenAction = self.createAction("&Open...", self.fileOpen,
                                           QKeySequence.Open, "fileopen",
                                           "Open an existing image file")
        fileSaveAction = self.createAction("&Save", self.fileSave,
                                           QKeySequence.Save, "filesave",
                                           "Save the image")
        fileSaveAsAction = self.createAction(
            "Save &As...",
            self.fileSaveAs,
            icon="filesaveas",
            tip="Save the image using a new name")
        filePrintAction = self.createAction("&Print", self.filePrint,
                                            QKeySequence.Print, "fileprint",
                                            "Print the image")
        fileQuitAction = self.createAction("&Quit", self.close, "Ctrl+Q",
                                           "filequit", "Close the application")
        editInvertAction = self.createAction("&Invert", None, "Ctrl+I",
                                             "editinvert",
                                             "Invert the image's colors", True)
        editInvertAction.toggled.connect(self.editInvert)
        editSwapRedAndBlueAction = self.createAction(
            "Sw&ap Red and Blue", None, "Ctrl+A", "editswap",
            "Swap the image's red and blue color components", True)
        editSwapRedAndBlueAction.toggled.connect(self.editSwapRedAndBlue)
        editZoomAction = self.createAction("&Zoom...", self.editZoom, "Alt+Z",
                                           "editzoom", "Zoom the image")
        mirrorGroup = QActionGroup(self)
        editUnMirrorAction = self.createAction("&Unmirror", None, "Ctrl+U",
                                               "editunmirror",
                                               "Unmirror the image", True)
        editUnMirrorAction.toggled.connect(self.editUnMirror)
        mirrorGroup.addAction(editUnMirrorAction)
        editMirrorHorizontalAction = self.createAction(
            "Mirror &Horizontally", None, "Ctrl+H", "editmirrorhoriz",
            "Horizontally mirror the image", True)
        editMirrorHorizontalAction.toggled.connect(self.editMirrorHorizontal)
        mirrorGroup.addAction(editMirrorHorizontalAction)
        editMirrorVerticalAction = self.createAction(
            "Mirror &Vertically", None, "Ctrl+V", "editmirrorvert",
            "Vertically mirror the image", True)
        editMirrorVerticalAction.toggled.connect(self.editMirrorVertical)
        mirrorGroup.addAction(editMirrorVerticalAction)
        editUnMirrorAction.setChecked(True)
        helpAboutAction = self.createAction("&About Image Changer",
                                            self.helpAbout)
        helpHelpAction = self.createAction("&Help", self.helpHelp,
                                           QKeySequence.HelpContents)

        self.fileMenu = self.menuBar().addMenu("&File")
        self.fileMenuActions = (fileNewAction, fileOpenAction, fileSaveAction,
                                fileSaveAsAction, None, filePrintAction,
                                fileQuitAction)
        self.fileMenu.aboutToShow.connect(self.updateFileMenu)
        editMenu = self.menuBar().addMenu("&Edit")
        self.addActions(
            editMenu,
            (editInvertAction, editSwapRedAndBlueAction, editZoomAction))
        mirrorMenu = editMenu.addMenu(QIcon(":/editmirror.png"), "&Mirror")
        self.addActions(mirrorMenu,
                        (editUnMirrorAction, editMirrorHorizontalAction,
                         editMirrorVerticalAction))
        helpMenu = self.menuBar().addMenu("&Help")
        self.addActions(helpMenu, (helpAboutAction, helpHelpAction))

        fileToolbar = self.addToolBar("File")
        fileToolbar.setObjectName("FileToolBar")
        self.addActions(fileToolbar,
                        (fileNewAction, fileOpenAction, fileSaveAsAction))
        editToolbar = self.addToolBar("Edit")
        editToolbar.setObjectName("EditToolBar")
        self.addActions(
            editToolbar,
            (editInvertAction, editSwapRedAndBlueAction, editUnMirrorAction,
             editMirrorVerticalAction, editMirrorHorizontalAction))
        self.zoomSpinBox = QSpinBox()
        self.zoomSpinBox.setRange(1, 400)
        self.zoomSpinBox.setSuffix(" %")
        self.zoomSpinBox.setValue(100)
        self.zoomSpinBox.setToolTip("Zoom the image")
        self.zoomSpinBox.setStatusTip(self.zoomSpinBox.toolTip())
        self.zoomSpinBox.setFocusPolicy(Qt.NoFocus)
        self.zoomSpinBox.valueChanged.connect(self.showImage)
        editToolbar.addWidget(self.zoomSpinBox)

        self.addActions(
            self.imageLabel,
            (editInvertAction, editSwapRedAndBlueAction, editUnMirrorAction,
             editMirrorVerticalAction, editMirrorHorizontalAction))

        self.resetableActions = ((editInvertAction,
                                  False), (editSwapRedAndBlueAction, False),
                                 (editUnMirrorAction, True))

    def load_settings(self):
        settings = QSettings()
        self.recentFiles = settings.value("RecentFiles").toStringList()
        self.restoreGeometry(
            settings.value("MainWindow/Geometry").toByteArray())
        self.restoreState(settings.value("MainWindow/State").toByteArray())

    def createAction(self,
                     text,
                     slot=None,
                     shortcut=None,
                     icon=None,
                     tip=None,
                     checkable=False):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/{0}.png".format(icon)))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            action.triggered.connect(slot)
        if checkable:
            action.setCheckable(True)
        return action

    def addActions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def closeEvent(self, event):
        if self.okToContinue():
            settings = QSettings()
            filename = (QVariant(QString(self.filename))
                        if self.filename is not None else QVariant())
            settings.setValue("LastFile", filename)
            recentFiles = (QVariant(self.recentFiles)
                           if self.recentFiles else QVariant())
            settings.setValue("RecentFiles", recentFiles)
            settings.setValue("MainWindow/Geometry",
                              QVariant(self.saveGeometry()))
            settings.setValue("MainWindow/State", QVariant(self.saveState()))
        else:
            event.ignore()

    def okToContinue(self):
        if self.dirty:
            reply = QMessageBox.question(
                self, "Image Changer - Unsaved Changes",
                "Save unsaved changes?",
                QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
            if reply == QMessageBox.Cancel:
                return False
            elif reply == QMessageBox.Yes:
                return self.fileSave()
        return True

    def loadInitialFile(self):
        settings = QSettings()
        fname = unicode(settings.value("LastFile").toString())
        if fname and QFile.exists(fname):
            self.loadFile(fname)

    def updateStatus(self, message):
        self.statusBar().showMessage(message, 5000)
        self.listWidget.addItem(message)
        if self.filename is not None:
            self.setWindowTitle("Image Changer - {0}[*]".format(
                os.path.basename(self.filename)))
        elif not self.image.isNull():
            self.setWindowTitle("Image Changer - Unnamed[*]")
        else:
            self.setWindowTitle("Image Changer[*]")
        self.setWindowModified(self.dirty)

    def updateFileMenu(self):
        self.fileMenu.clear()
        self.addActions(self.fileMenu, self.fileMenuActions[:-1])
        current = (QString(self.filename)
                   if self.filename is not None else None)
        recentFiles = []
        for fname in self.recentFiles:
            if fname != current and QFile.exists(fname):
                recentFiles.append(fname)
        if recentFiles:
            self.fileMenu.addSeparator()
            for i, fname in enumerate(recentFiles):
                action = QAction(
                    QIcon(":/icon.png"),
                    "&{0} {1}".format(i + 1,
                                      QFileInfo(fname).fileName()), self)
                action.setData(QVariant(fname))
                action.triggered.connect(self.loadFile)
                self.fileMenu.addAction(action)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.fileMenuActions[-1])

    def fileNew(self):
        if not self.okToContinue():
            return
        dialog = newimagedlg.NewImageDlg(self)
        if dialog.exec_():
            self.addRecentFile(self.filename)
            self.image = QImage()
            for action, check in self.resetableActions:
                action.setChecked(check)
            self.image = dialog.image()
            self.filename = None
            self.dirty = True
            self.showImage()
            self.sizeLabel.setText("{0} x {1}".format(self.image.width(),
                                                      self.image.height()))
            self.updateStatus("Created new image")

    def fileOpen(self):
        if not self.okToContinue():
            return
        dir = (os.path.dirname(self.filename)
               if self.filename is not None else ".")
        formats = ([
            "*.{0}".format(unicode(format).lower())
            for format in QImageReader.supportedImageFormats()
        ])
        fname = unicode(
            QFileDialog.getOpenFileName(
                self, "Image Changer - Choose Image", dir,
                "Image files ({0})".format(" ".join(formats))))
        if fname:
            self.loadFile(fname)

    def loadFile(self, fname=None):
        if fname is None:
            action = self.sender()
            if isinstance(action, QAction):
                fname = unicode(action.data().toString())
                if not self.okToContinue():
                    return
            else:
                return
        if fname:
            self.filename = None
            image = QImage(fname)
            if image.isNull():
                message = "Failed to read {0}".format(fname)
            else:
                self.addRecentFile(fname)
                self.image = QImage()
                for action, check in self.resetableActions:
                    action.setChecked(check)
                self.image = image
                self.filename = fname
                self.showImage()
                self.dirty = False
                self.sizeLabel.setText("{0} x {1}".format(
                    image.width(), image.height()))
                message = "Loaded {0}".format(os.path.basename(fname))
            self.updateStatus(message)

    def addRecentFile(self, fname):
        if fname is None:
            return
        if not self.recentFiles.contains(fname):
            self.recentFiles.prepend(QString(fname))
            while self.recentFiles.count() > 9:
                self.recentFiles.takeLast()

    def fileSave(self):
        if self.image.isNull():
            return True
        if self.filename is None:
            return self.fileSaveAs()
        else:
            if self.image.save(self.filename, None):
                self.updateStatus("Saved as {0}".format(self.filename))
                self.dirty = False
                return True
            else:
                self.updateStatus("Failed to save {0}".format(self.filename))
                return False

    def fileSaveAs(self):
        if self.image.isNull():
            return True
        fname = self.filename if self.filename is not None else "."
        formats = ([
            "*.{0}".format(unicode(format).lower())
            for format in QImageWriter.supportedImageFormats()
        ])
        fname = unicode(
            QFileDialog.getSaveFileName(
                self, "Image Changer - Save Image", fname,
                "Image files ({0})".format(" ".join(formats))))
        if fname:
            if "." not in fname:
                fname += ".png"
            self.addRecentFile(fname)
            self.filename = fname
            return self.fileSave()
        return False

    def filePrint(self):
        if self.image.isNull():
            return
        if self.printer is None:
            self.printer = QPrinter(QPrinter.HighResolution)
            self.printer.setPageSize(QPrinter.Letter)
        form = QPrintDialog(self.printer, self)
        if form.exec_():
            painter = QPainter(self.printer)
            rect = painter.viewport()
            size = self.image.size()
            size.scale(rect.size(), Qt.KeepAspectRatio)
            painter.setViewport(rect.x(), rect.y(), size.width(),
                                size.height())
            painter.drawImage(0, 0, self.image)

    def editInvert(self, on):
        if self.image.isNull():
            return
        self.image.invertPixels()
        self.showImage()
        self.dirty = True
        self.updateStatus("Inverted" if on else "Uninverted")

    def editSwapRedAndBlue(self, on):
        if self.image.isNull():
            return
        self.image = self.image.rgbSwapped()
        self.showImage()
        self.dirty = True
        self.updateStatus(
            ("Swapped Red and Blue" if on else "Unswapped Red and Blue"))

    def editUnMirror(self, on):
        if self.image.isNull():
            return
        if self.mirroredhorizontally:
            self.editMirrorHorizontal(False)
        if self.mirroredvertically:
            self.editMirrorVertical(False)

    def editMirrorHorizontal(self, on):
        if self.image.isNull():
            return
        self.image = self.image.mirrored(True, False)
        self.showImage()
        self.mirroredhorizontally = not self.mirroredhorizontally
        self.dirty = True
        self.updateStatus(
            ("Mirrored Horizontally" if on else "Unmirrored Horizontally"))

    def editMirrorVertical(self, on):
        if self.image.isNull():
            return
        self.image = self.image.mirrored(False, True)
        self.showImage()
        self.mirroredvertically = not self.mirroredvertically
        self.dirty = True
        self.updateStatus(
            ("Mirrored Vertically" if on else "Unmirrored Vertically"))

    def editZoom(self):
        if self.image.isNull():
            return
        percent, ok = QInputDialog.getInteger(self, "Image Changer - Zoom",
                                              "Percent:",
                                              self.zoomSpinBox.value(), 1, 400)
        if ok:
            self.zoomSpinBox.setValue(percent)

    def showImage(self, percent=None):
        if self.image.isNull():
            return
        if percent is None:
            percent = self.zoomSpinBox.value()
        factor = percent / 100.0
        width = self.image.width() * factor
        height = self.image.height() * factor
        image = self.image.scaled(width, height, Qt.KeepAspectRatio)
        self.imageLabel.setPixmap(QPixmap.fromImage(image))

    def helpAbout(self):
        QMessageBox.about(
            self, "About Image Changer", """<b>Image Changer</b> v {0}
                <p>Copyright &copy; 2008-14 Qtrac Ltd. 
                All rights reserved.
                <p>This application can be used to perform
                simple image manipulations.
                <p>Python {1} - Qt {2} - PyQt {3} on {4}""".format(
                __version__, platform.python_version(), QT_VERSION_STR,
                PYQT_VERSION_STR, platform.system()))

    def helpHelp(self):
        form = helpform.HelpForm("index.html", self)
        form.show()
Example #2
0
 def createWidget(self, parent):
     w = QSpinBox(parent, buttonSymbols=QSpinBox.NoButtons)
     w.setFocusPolicy(Qt.ClickFocus)
     w.valueChanged[int].connect(self.slotValueChanged)
     return w
Example #3
0
class Window(QMainWindow):

  def __init__(self, parent=None):
    super(Window, self).__init__(parent)
    self.image = QImage()
    self.dirty = False
    self.filename = None
    self.dbFilename = None
    self.mirroredvertically = False
    self.mirroredhorizontally = False
    self.printer = None
    self.exampleForm= None
    self.matlPopup= None
    self.matlPropsHere= None
    self.create_widgets()
    self.create_actions()
    self.load_settings()
    self.setWindowTitle("Thermapythia")
    self.updateFileMenu()
    self.openStackupDB()
    QTimer.singleShot(0, self.loadInitialFile)


  def create_widgets(self):
    self.imageLabel = QLabel()
    self.imageLabel.setMinimumSize(200, 200)
    self.imageLabel.setAlignment(Qt.AlignCenter)
    self.imageLabel.setContextMenuPolicy(Qt.ActionsContextMenu)
    self.setCentralWidget(self.imageLabel)

    logDockWidget = QDockWidget("Log", self)
    logDockWidget.setObjectName("LogDockWidget")
    logDockWidget.setAllowedAreas(Qt.LeftDockWidgetArea|
                                  Qt.RightDockWidgetArea)
    self.listWidget = QListWidget()
    logDockWidget.setWidget(self.listWidget)
    self.addDockWidget(Qt.RightDockWidgetArea, logDockWidget)

    self.sizeLabel = QLabel()
    self.sizeLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
    status = self.statusBar()
    status.setSizeGripEnabled(False)
    status.addPermanentWidget(self.sizeLabel)
    status.showMessage("Ready", 5000)


  def create_actions(self):
    fileNewAction = self.createAction("&New...", self.fileNew,
                                      QKeySequence.New, "filenew", "Create an image file")
    fileOpenAction = self.createAction("&Open...", self.fileOpen,
                                       QKeySequence.Open, "fileopen",
                                       "Open an existing image file")
    fileSaveAction = self.createAction("&Save", self.fileSave,
                                       QKeySequence.Save, "filesave", "Save the image")
    fileSaveAsAction = self.createAction("Save &As...",
                                         self.fileSaveAs, icon="filesaveas",
                                         tip="Save the image using a new name")
    filePrintAction = self.createAction("&Print", self.filePrint,
                                        QKeySequence.Print, "fileprint", "Print the image")
    fileQuitAction = self.createAction("&Quit", self.close,
                                       "Ctrl+Q", "filequit", "Close the application")
    
    
    
    
    # createAction(String, slot, shortcut, icon, tip, checkable
    matlEditAction = self.createAction("&Materials", self.matlEdit, 
                                      None, "matls", "Edit materials")
    layerEditAction= self.createAction("&Layers", self.layerEdit, 
                                      None, "layers", "Edit layers") 
    viaEditAction= self.createAction("&Vias", self.viaEdit, 
                                      None, "vias", "Edit vias")  
    zzzEditAction= self.createAction("&Zzz", self.zzzEdit, 
                                     None, "zzz", "Edit zzz")     
    
    
    
    editInvertAction = self.createAction("&Invert", None, "Ctrl+I",
                                         "editinvert", "Invert the image's colors", True)
    editInvertAction.toggled.connect(self.editInvert)
    editSwapRedAndBlueAction = self.createAction("Sw&ap Red and Blue",
                                                 None, "Ctrl+A", "editswap",
                                                 "Swap the image's red and blue color components", True)
    editSwapRedAndBlueAction.toggled.connect(self.editSwapRedAndBlue)
    editZoomAction = self.createAction("&Zoom...", self.editZoom,
                                       "Alt+Z", "editzoom", "Zoom the image")
    mirrorGroup = QActionGroup(self)
    editUnMirrorAction = self.createAction("&Unmirror", None, "Ctrl+U",
                                           "editunmirror", "Unmirror the image", True)
    editUnMirrorAction.toggled.connect(self.editUnMirror)
    mirrorGroup.addAction(editUnMirrorAction)
    editMirrorHorizontalAction = self.createAction(
      "Mirror &Horizontally", None, "Ctrl+H", "editmirrorhoriz",
      "Horizontally mirror the image", True)
    editMirrorHorizontalAction.toggled.connect(
      self.editMirrorHorizontal)
    mirrorGroup.addAction(editMirrorHorizontalAction)
    editMirrorVerticalAction = self.createAction("Mirror &Vertically",
                                                 None, "Ctrl+V", "editmirrorvert",
                                                 "Vertically mirror the image", True)
    editMirrorVerticalAction.toggled.connect(self.editMirrorVertical)
    mirrorGroup.addAction(editMirrorVerticalAction)
    editUnMirrorAction.setChecked(True)
    helpAboutAction = self.createAction("&About Thermapythia",
                                        self.helpAbout)
    helpHelpAction = self.createAction("&Help", self.helpHelp,
                                       QKeySequence.HelpContents)

    self.fileMenu = self.menuBar().addMenu("&File")
    self.fileMenuActions = (fileNewAction, fileOpenAction,
                            fileSaveAction, fileSaveAsAction, None, filePrintAction,
                            fileQuitAction)
    self.fileMenu.aboutToShow.connect(self.updateFileMenu)
    
    stackupMenu = self.menuBar().addMenu("&Stackup")
    self.addActions(stackupMenu, (matlEditAction, layerEditAction, viaEditAction))
    
    
    editMenu = self.menuBar().addMenu("&Edit")
    self.addActions(editMenu, (editInvertAction,
                               editSwapRedAndBlueAction, editZoomAction))
    
    
    mirrorMenu = editMenu.addMenu(QIcon(":/editmirror.png"),
                                  "&Mirror")
    self.addActions(mirrorMenu, (editUnMirrorAction,
                                 editMirrorHorizontalAction, editMirrorVerticalAction))
    helpMenu = self.menuBar().addMenu("&Help")
    self.addActions(helpMenu, (helpAboutAction, helpHelpAction))

    fileToolbar = self.addToolBar("File")
    fileToolbar.setObjectName("FileToolBar")
    self.addActions(fileToolbar, (fileNewAction, fileOpenAction,
                                  fileSaveAsAction))
    
    stackupToolbar = self.addToolBar("Stackup")
    stackupToolbar.setObjectName("StackupToolBar")
    self.addActions(stackupToolbar, (matlEditAction, layerEditAction, viaEditAction))
    
    editToolbar = self.addToolBar("Edit")
    editToolbar.setObjectName("EditToolBar")
    self.addActions(editToolbar, (editInvertAction,
                                  editSwapRedAndBlueAction, editUnMirrorAction,
                                  editMirrorVerticalAction, editMirrorHorizontalAction))
    self.zoomSpinBox = QSpinBox()
    self.zoomSpinBox.setRange(1, 400)
    self.zoomSpinBox.setSuffix(" %")
    self.zoomSpinBox.setValue(100)
    self.zoomSpinBox.setToolTip("Zoom the image")
    self.zoomSpinBox.setStatusTip(self.zoomSpinBox.toolTip())
    self.zoomSpinBox.setFocusPolicy(Qt.NoFocus)
    self.zoomSpinBox.valueChanged.connect(self.showImage)
    editToolbar.addWidget(self.zoomSpinBox)

    self.addActions(self.imageLabel, (editInvertAction,
                                      editSwapRedAndBlueAction, editUnMirrorAction,
                                      editMirrorVerticalAction, editMirrorHorizontalAction))

    self.resetableActions = ((editInvertAction, False),
                             (editSwapRedAndBlueAction, False),
                             (editUnMirrorAction, True))


  def load_settings(self):
    settings = QSettings()
    self.recentFiles = settings.value("RecentFiles").toStringList()
    self.restoreGeometry(
      settings.value("MainWindow/Geometry").toByteArray())
    self.restoreState(settings.value("MainWindow/State").toByteArray())


  def createAction(self, text, slot=None, shortcut=None, icon=None,
                   tip=None, checkable=False):
    action = QAction(text, self)
    if icon is not None:
      action.setIcon(QIcon(":/{0}.png".format(icon)))
    if shortcut is not None:
      action.setShortcut(shortcut)
    if tip is not None:
      action.setToolTip(tip)
      action.setStatusTip(tip)
    if slot is not None:
      action.triggered.connect(slot)
    if checkable:
      action.setCheckable(True)
    return action


  def addActions(self, target, actions):
    for action in actions:
      if action is None:
        target.addSeparator()
      else:
        target.addAction(action)


  def closeEvent(self, event):
    if self.okToContinue():
      settings = QSettings()
      filename = (QVariant(QString(self.filename))
                  if self.filename is not None else QVariant())
      settings.setValue("LastFile", filename)
      recentFiles = (QVariant(self.recentFiles)
                     if self.recentFiles else QVariant())
      settings.setValue("RecentFiles", recentFiles)
      settings.setValue("MainWindow/Geometry", QVariant(
        self.saveGeometry()))
      settings.setValue("MainWindow/State", QVariant(
        self.saveState()))
    else:
      event.ignore()


  def okToContinue(self):
    if self.dirty:
      reply = QMessageBox.question(self,
                                   "Thermapythia - Unsaved Changes",
                                   "Save unsaved changes?",
                                   QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel)
      if reply == QMessageBox.Cancel:
        return False
      elif reply == QMessageBox.Yes:
        return self.fileSave()
    return True


  def loadInitialFile(self):
    settings = QSettings()
    fname = unicode(settings.value("LastFile").toString())
    if fname and QFile.exists(fname):
      self.loadFile(fname)


  def updateStatus(self, message):
    self.statusBar().showMessage(message, 5000)
    self.listWidget.addItem(message)
    if self.filename is not None:
      self.setWindowTitle("Thermapythia - {0}[*]".format(
        os.path.basename(self.filename)))
    elif not self.image.isNull():
      self.setWindowTitle("Thermapythia - Unnamed[*]")
    else:
      self.setWindowTitle("Thermapythia[*]")
    self.setWindowModified(self.dirty)

  def updateFileMenu(self):
    self.fileMenu.clear()
    self.addActions(self.fileMenu, self.fileMenuActions[:-1])
    current = (QString(self.filename)
               if self.filename is not None else None)
    recentFiles = []
    for fname in self.recentFiles:
      if fname != current and QFile.exists(fname):
        recentFiles.append(fname)
    if recentFiles:
      self.fileMenu.addSeparator()
      for i, fname in enumerate(recentFiles):
        action = QAction(QIcon(":/icon.png"),
                         "&{0} {1}".format(i + 1, QFileInfo(
                           fname).fileName()), self)
        action.setData(QVariant(fname))
        action.triggered.connect(self.loadFile)
        self.fileMenu.addAction(action)
    self.fileMenu.addSeparator()
    self.fileMenu.addAction(self.fileMenuActions[-1])

  def fileNew(self):
    if not self.okToContinue():
      return
    dialog = newimagedlg.NewImageDlg(self)
    if dialog.exec_():
      self.addRecentFile(self.filename)
      self.image = QImage()
      for action, check in self.resetableActions:
        action.setChecked(check)
      self.image = dialog.image()
      self.filename = None
      self.dirty = True
      self.showImage()
      self.sizeLabel.setText("{0} x {1}".format(self.image.width(),
                                                self.image.height()))
      self.updateStatus("Created new image")


  def fileOpen(self):
    if not self.okToContinue():
      return
    dir = (os.path.dirname(self.filename)
           if self.filename is not None else ".")
    formats = (["*.{0}".format(unicode(format).lower())
                for format in QImageReader.supportedImageFormats()])
    fname = unicode(QFileDialog.getOpenFileName(self,
                                                "Thermapythia - Choose Image", dir,
                                                "Image files ({0})".format(" ".join(formats))))
    if fname:
      self.loadFile(fname)


  def loadFile(self, fname=None):
    if fname is None:
      action = self.sender()
      if isinstance(action, QAction):
        fname = unicode(action.data().toString())
        if not self.okToContinue():
          return
      else:
        return
    if fname:
      self.filename = None
      image = QImage(fname)
      if image.isNull():
        message = "Failed to read {0}".format(fname)
      else:
        self.addRecentFile(fname)
        self.image = QImage()
        for action, check in self.resetableActions:
          action.setChecked(check)
        self.image = image
        self.filename = fname
        self.showImage()
        self.dirty = False
        self.sizeLabel.setText("{0} x {1}".format(
          image.width(), image.height()))
        message = "Loaded {0}".format(os.path.basename(fname))
      self.updateStatus(message)


  def addRecentFile(self, fname):
    if fname is None:
      return
    if not self.recentFiles.contains(fname):
      self.recentFiles.prepend(QString(fname))
      while self.recentFiles.count() > 9:
        self.recentFiles.takeLast()


  def fileSave(self):
    if self.image.isNull():
      return True
    if self.filename is None:
      return self.fileSaveAs()
    else:
      if self.image.save(self.filename, None):
        self.updateStatus("Saved as {0}".format(self.filename))
        self.dirty = False
        return True
      else:
        self.updateStatus("Failed to save {0}".format(
          self.filename))
        return False


  def fileSaveAs(self):
    if self.image.isNull():
      return True
    fname = self.filename if self.filename is not None else "."
    formats = (["*.{0}".format(unicode(format).lower())
                for format in QImageWriter.supportedImageFormats()])
    fname = unicode(QFileDialog.getSaveFileName(self,
                                                "Thermapythia - Save Image", fname,
                                                "Image files ({0})".format(" ".join(formats))))
    if fname:
      if "." not in fname:
        fname += ".png"
      self.addRecentFile(fname)
      self.filename = fname
      return self.fileSave()
    return False


  def filePrint(self):
    if self.image.isNull():
      return
    if self.printer is None:
      self.printer = QPrinter(QPrinter.HighResolution)
      self.printer.setPageSize(QPrinter.Letter)
    form = QPrintDialog(self.printer, self)
    if form.exec_():
      painter = QPainter(self.printer)
      rect = painter.viewport()
      size = self.image.size()
      size.scale(rect.size(), Qt.KeepAspectRatio)
      painter.setViewport(rect.x(), rect.y(), size.width(),
                          size.height())
      painter.drawImage(0, 0, self.image)
  
  
  
  #
  def openStackupDB(self):
  
    if self.dbFilename != None:
      return
    self.dbFilename = os.path.join(os.path.dirname(__file__), "stackup.db")
    create = not QFile.exists(self.dbFilename)
  
    db = QSqlDatabase.addDatabase("QSQLITE")
    db.setDatabaseName(self.dbFilename)
    if not db.open():
      QMessageBox.warning(None, "Can't open stackup database",
                          QString("Database Error: %1").arg(db.lastError().text()))
      sys.exit(1)  
    if create == False:
      self.updateStatus("Found stackup database file: " + str(self.dbFilename))
      
    self.createDatabaseTables()
      
    with open('test2.js', "r") as jsonHandle:
      jsonContents= jsonHandle.read()    
    config= yaml.load(jsonContents)    
      
    matlCount= self.countDatabaseTableRows("matl")
    if matlCount == 0:
      self.updateStatus("material editor call goes here.")
      #
      # TODO: Put the guess-what-I'm thinking Qt table editor thing here.
      #
      # self.loadDefaultMatls()
      matls = Matls.Matls(config['matl_config'])
      self.loadDefaultData('matl', matls)      
      
    viaCount= self.countDatabaseTableRows("via")
    if viaCount == 0:  
      vias = Vias.Vias(config['via_config'])
      self.loadDefaultData('via', vias)
      
    layerCount= self.countDatabaseTableRows("layer")
    if layerCount == 0:  
      layers = Layers.Layers(config['layer_config'])
      self.loadDefaultData('layer', layers)
      
    # initialize zzz new content here, perhaps
  
  def createDatabaseTables(self):
    query = QSqlQuery()
    self.updateStatus("Creating database tables")
          # "id" INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
    statusMatl = query.exec_("""CREATE TABLE IF NOT EXISTS "matl" (
                  "name" TEXT,
                  "type" TEXT,
                  "density" real,
                  "color" TEXT,
                  "specific_heat" real,
                  "conductivity" real,
                  "conductivityXX" real,
                  "conductivityYY" real,
                  "conductivityZZ" real,
                  "reflection_coeff" real,
                  "emissivity" real,
                  "max_height" real,
                  "thickness" real
                  );""")
    if statusMatl == False:
      self.updateStatus("Could not create material property database table 'matl'")
      self.updateStatus("Database error message: " + query.lastError().text())
    
    statusPhylayer = query.exec_("""CREATE TABLE IF NOT EXISTS "layer" (
                  "id" INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
                  "name" TEXT,
                  "matl" TEXT,
                  "type" TEXT,
                  "thickness" real,
                  "displaces" TEXT,
                  "coverage" real,
                  "z_bottom" real,
                  "z_top" real,
                  "adheres_to" TEXT);""")
    if statusPhylayer == False:
      self.updateStatus("Could not create material property database table 'layer'")
      self.updateStatus("Database error message: " + query.lastError().text())  
    
    statusVia = query.exec_("""CREATE TABLE IF NOT EXISTS "via" (
                  "id" INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
                  "name" TEXT,
                  "matl" TEXT,
                  "to" TEXT,
                  "from" TEXT);""")
    if statusVia == False:
      self.updateStatus("Could not create material property database table 'via'")
      self.updateStatus("Database error message: " + query.lastError().text())      
    
  def countDatabaseTableRows(self, tablename):
    query = QSqlQuery()
    self.updateStatus("Loading database tables")    
    query.prepare("select count(*) from " + tablename + ";")
    status = query.exec_()
    if status == False:
      self.updateStatus("Could not count entries in table '" + tablename + "'")
      self.updateStatus("Database error message: " + query.lastError().text())
    query.first()
    count, ok = query.value(0).toInt()
    # self.updateStatus("There are " + str(count) + " rows in the " + tablename + " table")
    return count

  def loadDefaultData(self, table, data):
    query = QSqlQuery()
    insertList= "', '".join(data.tableCols)
    insertList= "'" + insertList + "'"    
    colCount= len(data.tableCols)
    quest= ""
    for i in range(0, colCount):
      quest = quest + "?,"
    quest= quest[:-1]
    
    sql= "INSERT INTO " + table + "(" + insertList + ") VALUES (" + quest + ");"
    # self.updateStatus(sql)
    status= query.prepare(sql)
    if status == False:
      self.updateStatus("Could not prepare material property database table " + table)
      self.updateStatus("Database error message: " + query.lastError().text())    
    
    for row in data.propDict:
      for prop in data.tableCols:
        propval= data.propDict[row][prop]
        if data.tableColSQLTypes[prop] == 'TEXT':
          query.addBindValue(QVariant(QString(propval)))
          # self.updateStatus("Setting TEXT property " + prop + " to value " + str(propval) + " in row " + str(row))
        elif data.tableColSQLTypes[prop] == 'real':
          if (propval == '-'):
            propreal= -999.9
          else:
            propreal= float(propval)
          query.addBindValue(QVariant(propreal))
          # self.updateStatus("Setting real property " + prop + " to value " + str(propreal) + " in row " + str(row))
      status= query.exec_()
      if status == False:
        self.updateStatus("Could not load property database table " + table + " with " + str(row))
        self.updateStatus("Database error message: " + query.lastError().text())
 
 
 
  def matlEdit(self):
    self.dirty= True
    self.updateStatus("Call edit material code here")
    # This ends up in a little child window
    
    
    self.matlPopup= QLabel("<font color=green size=72><b> Material Editor </b></font>")
    # self.matlPopup.setWindowFlags(Qt.SplashScreen)
    self.matlPopup.setWindowTitle("Material edit popup")
    
    self.matlPropsHere= QLabel("<font color=red size=24><b> Data goes here </b></font>")
    # self.matlPopup.setWindowFlags(Qt.SplashScreen) 
    
    if 1 == 0:
      dataLayout= QVBoxLayout()
      dataLayout.addWidget(self.matlPopup)
      dataLayout.addWidget(self.matlPropsHere)
      self.setLayout(dataLayout)    
    
    self.matlPopup.show()
    self.matlPropsHere.show()
    
#    self.exampleForm= MatlForm()
    # First need a layout manager, and add the widget to that. 
    # Then attach the layout manager to a window.
    # addWidget(self.exampleForm)
#    self.exampleForm.show()
    
    QTimer.singleShot(5000, self.update)
    
    self.updateStatus("Created stackup db")
    
  def layerEdit(self):
    self.dirty= True
    self.updateStatus("Call edit layer code here") 
    
    # This way of doing it is modal - window doesn't go away and covers up other windows until it is dismissed.
    form= MatlForm()
    form.exec_()
    

  def viaEdit(self):
    self.dirty= True
    self.updateStatus("Call edit via code here")

  def zzzEdit(self):
    self.dirty= True
    self.updateStatus("Call code to be triggered by zzz button here")         

  def editInvert(self, on):
    if self.image.isNull():
      return
    self.image.invertPixels()
    self.showImage()
    self.dirty = True
    self.updateStatus("Inverted" if on else "Uninverted")
       

  def editSwapRedAndBlue(self, on):
    if self.image.isNull():
      return
    self.image = self.image.rgbSwapped()
    self.showImage()
    self.dirty = True
    self.updateStatus(("Swapped Red and Blue"
                       if on else "Unswapped Red and Blue"))


  def editUnMirror(self, on):
    if self.image.isNull():
      return
    if self.mirroredhorizontally:
      self.editMirrorHorizontal(False)
    if self.mirroredvertically:
      self.editMirrorVertical(False)


  def editMirrorHorizontal(self, on):
    if self.image.isNull():
      return
    self.image = self.image.mirrored(True, False)
    self.showImage()
    self.mirroredhorizontally = not self.mirroredhorizontally
    self.dirty = True
    self.updateStatus(("Mirrored Horizontally"
                       if on else "Unmirrored Horizontally"))


  def editMirrorVertical(self, on):
    if self.image.isNull():
      return
    self.image = self.image.mirrored(False, True)
    self.showImage()
    self.mirroredvertically = not self.mirroredvertically
    self.dirty = True
    self.updateStatus(("Mirrored Vertically"
                       if on else "Unmirrored Vertically"))


  def editZoom(self):
    if self.image.isNull():
      return
    percent, ok = QInputDialog.getInteger(self,
                                          "Thermapythia - Zoom", "Percent:",
                                          self.zoomSpinBox.value(), 1, 400)
    if ok:
      self.zoomSpinBox.setValue(percent)


  def showImage(self, percent=None):
    if self.image.isNull():
      return
    if percent is None:
      percent = self.zoomSpinBox.value()
    factor = percent / 100.0
    width = self.image.width() * factor
    height = self.image.height() * factor
    image = self.image.scaled(width, height, Qt.KeepAspectRatio)
    self.imageLabel.setPixmap(QPixmap.fromImage(image))


  def helpAbout(self):
    QMessageBox.about(self, "About Thermapythia",
                      """<b>Thermapythia</b> v {0}
                <p>Thermal Analyzer in Python predicts circuit board temperature
                <p>Python {1} - Qt {2} - PyQt {3} on {4}""".format(
                                                             __version__, platform.python_version(),
                                                             QT_VERSION_STR, PYQT_VERSION_STR,
                                                             platform.system()))


  def helpHelp(self):
    form = HelpForm.HelpForm("index.html", self)
    form.show()
class Window(QMainWindow):

    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.image = QImage()
        self.dirty = False
        self.filename = None
        self.mirroredvertically = False
        self.mirroredhorizontally = False
        self.printer = None
        self.create_widgets()
        self.create_actions()
        self.load_settings()
        self.setWindowTitle("Image Changer")
        self.updateFileMenu()
        QTimer.singleShot(0, self.loadInitialFile)


    def create_widgets(self):
        self.imageLabel = QLabel()
        self.imageLabel.setMinimumSize(200, 200)
        self.imageLabel.setAlignment(Qt.AlignCenter)
        self.imageLabel.setContextMenuPolicy(Qt.ActionsContextMenu)
        self.setCentralWidget(self.imageLabel)

        logDockWidget = QDockWidget("Log", self)
        logDockWidget.setObjectName("LogDockWidget")
        logDockWidget.setAllowedAreas(Qt.LeftDockWidgetArea|
                                      Qt.RightDockWidgetArea)
        self.listWidget = QListWidget()
        logDockWidget.setWidget(self.listWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, logDockWidget)

        self.sizeLabel = QLabel()
        self.sizeLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
        status = self.statusBar()
        status.setSizeGripEnabled(False)
        status.addPermanentWidget(self.sizeLabel)
        status.showMessage("Ready", 5000)


    def create_actions(self):
        fileNewAction = self.createAction("&New...", self.fileNew,
                QKeySequence.New, "filenew", "Create an image file")
        fileOpenAction = self.createAction("&Open...", self.fileOpen,
                QKeySequence.Open, "fileopen",
                "Open an existing image file")
        fileSaveAction = self.createAction("&Save", self.fileSave,
                QKeySequence.Save, "filesave", "Save the image")
        fileSaveAsAction = self.createAction("Save &As...",
                self.fileSaveAs, icon="filesaveas",
                tip="Save the image using a new name")
        filePrintAction = self.createAction("&Print", self.filePrint,
                QKeySequence.Print, "fileprint", "Print the image")
        fileQuitAction = self.createAction("&Quit", self.close,
                "Ctrl+Q", "filequit", "Close the application")
        editInvertAction = self.createAction("&Invert", None, "Ctrl+I",
                "editinvert", "Invert the image's colors", True)
        editInvertAction.toggled.connect(self.editInvert)
        editSwapRedAndBlueAction = self.createAction("Sw&ap Red and Blue",
                None, "Ctrl+A", "editswap",
                "Swap the image's red and blue color components", True)
        editSwapRedAndBlueAction.toggled.connect(self.editSwapRedAndBlue)
        editZoomAction = self.createAction("&Zoom...", self.editZoom,
                "Alt+Z", "editzoom", "Zoom the image")
        editResizeAction = self.createAction("&Resize...",
                self.editResize, "Ctrl+R", "editresize",
                "Resize the image")
        mirrorGroup = QActionGroup(self)
        editUnMirrorAction = self.createAction("&Unmirror", None, "Ctrl+U",
                "editunmirror", "Unmirror the image", True)
        editUnMirrorAction.toggled.connect(self.editUnMirror)
        mirrorGroup.addAction(editUnMirrorAction)
        editMirrorHorizontalAction = self.createAction(
                "Mirror &Horizontally", None, "Ctrl+H", "editmirrorhoriz",
                "Horizontally mirror the image", True)
        editMirrorHorizontalAction.toggled.connect(
                self.editMirrorHorizontal)
        mirrorGroup.addAction(editMirrorHorizontalAction)
        editMirrorVerticalAction = self.createAction( "Mirror &Vertically",
                None, "Ctrl+V", "editmirrorvert",
                "Vertically mirror the image", True)
        editMirrorVerticalAction.toggled.connect(self.editMirrorVertical)
        mirrorGroup.addAction(editMirrorVerticalAction)
        editUnMirrorAction.setChecked(True)
        helpAboutAction = self.createAction("&About Image Changer",
                self.helpAbout)
        helpHelpAction = self.createAction("&Help", self.helpHelp,
                QKeySequence.HelpContents)

        self.fileMenu = self.menuBar().addMenu("&File")
        self.fileMenuActions = (fileNewAction, fileOpenAction,
                fileSaveAction, fileSaveAsAction, None, filePrintAction,
                fileQuitAction)
        self.fileMenu.aboutToShow.connect(self.updateFileMenu)
        editMenu = self.menuBar().addMenu("&Edit")
        self.addActions(editMenu, (editInvertAction,
                editSwapRedAndBlueAction, editZoomAction,
                editResizeAction))
        mirrorMenu = editMenu.addMenu(QIcon(":/editmirror.png"),
                                      "&Mirror")
        self.addActions(mirrorMenu, (editUnMirrorAction,
                editMirrorHorizontalAction, editMirrorVerticalAction))
        helpMenu = self.menuBar().addMenu("&Help")
        self.addActions(helpMenu, (helpAboutAction, helpHelpAction))

        fileToolbar = self.addToolBar("File")
        fileToolbar.setObjectName("FileToolBar")
        self.addActions(fileToolbar, (fileNewAction, fileOpenAction,
                                      fileSaveAsAction))
        editToolbar = self.addToolBar("Edit")
        editToolbar.setObjectName("EditToolBar")
        self.addActions(editToolbar, (editInvertAction,
                editSwapRedAndBlueAction, editUnMirrorAction,
                editMirrorVerticalAction, editMirrorHorizontalAction))
        self.zoomSpinBox = QSpinBox()
        self.zoomSpinBox.setRange(1, 400)
        self.zoomSpinBox.setSuffix(" %")
        self.zoomSpinBox.setValue(100)
        self.zoomSpinBox.setToolTip("Zoom the image")
        self.zoomSpinBox.setStatusTip(self.zoomSpinBox.toolTip())
        self.zoomSpinBox.setFocusPolicy(Qt.NoFocus)
        self.zoomSpinBox.valueChanged.connect(self.showImage)
        editToolbar.addWidget(self.zoomSpinBox)

        self.addActions(self.imageLabel, (editInvertAction,
                editSwapRedAndBlueAction, editUnMirrorAction,
                editMirrorVerticalAction, editMirrorHorizontalAction))

        self.resetableActions = ((editInvertAction, False),
                                 (editSwapRedAndBlueAction, False),
                                 (editUnMirrorAction, True))


    def load_settings(self):
        settings = QSettings()
        self.recentFiles = settings.value("RecentFiles").toStringList()
        self.restoreGeometry(
                settings.value("MainWindow/Geometry").toByteArray())
        self.restoreState(settings.value("MainWindow/State").toByteArray())


    def createAction(self, text, slot=None, shortcut=None, icon=None,
                     tip=None, checkable=False):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/{0}.png".format(icon)))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            action.triggered.connect(slot)
        if checkable:
            action.setCheckable(True)
        return action


    def addActions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)


    def closeEvent(self, event):
        if self.okToContinue():
            settings = QSettings()
            filename = (QVariant(QString(self.filename)) 
                        if self.filename is not None else QVariant())
            settings.setValue("LastFile", filename)
            recentFiles = (QVariant(self.recentFiles)
                           if self.recentFiles else QVariant())
            settings.setValue("RecentFiles", recentFiles)
            settings.setValue("MainWindow/Geometry", QVariant(
                              self.saveGeometry()))
            settings.setValue("MainWindow/State", QVariant(
                              self.saveState()))
        else:
            event.ignore()


    def okToContinue(self):
        if self.dirty:
            reply = QMessageBox.question(self,
                    "Image Changer - Unsaved Changes",
                    "Save unsaved changes?",
                    QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel)
            if reply == QMessageBox.Cancel:
                return False
            elif reply == QMessageBox.Yes:
                return self.fileSave()
        return True


    def loadInitialFile(self):
        settings = QSettings()
        fname = unicode(settings.value("LastFile").toString())
        if fname and QFile.exists(fname):
            self.loadFile(fname)


    def updateStatus(self, message):
        self.statusBar().showMessage(message, 5000)
        self.listWidget.addItem(message)
        if self.filename is not None:
            self.setWindowTitle("Image Changer - {0}[*]".format(
                                os.path.basename(self.filename)))
        elif not self.image.isNull():
            self.setWindowTitle("Image Changer - Unnamed[*]")
        else:
            self.setWindowTitle("Image Changer[*]")
        self.setWindowModified(self.dirty)


    def updateFileMenu(self):
        self.fileMenu.clear()
        self.addActions(self.fileMenu, self.fileMenuActions[:-1])
        current = (QString(self.filename)
                   if self.filename is not None else None)
        recentFiles = []
        for fname in self.recentFiles:
            if fname != current and QFile.exists(fname):
                recentFiles.append(fname)
        if recentFiles:
            self.fileMenu.addSeparator()
            for i, fname in enumerate(recentFiles):
                action = QAction(QIcon(":/icon.png"),
                        "&{0} {1}".format(i + 1, QFileInfo(
                        fname).fileName()), self)
                action.setData(QVariant(fname))
                action.triggered.connect(self.loadFile)
                self.fileMenu.addAction(action)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.fileMenuActions[-1])


    def fileNew(self):
        if not self.okToContinue():
            return
        dialog = newimagedlg.NewImageDlg(self)
        if dialog.exec_():
            self.addRecentFile(self.filename)
            self.image = QImage()
            for action, check in self.resetableActions:
                action.setChecked(check)
            self.image = dialog.image()
            self.filename = None
            self.dirty = True
            self.showImage()
            self.sizeLabel.setText("{0} x {1}".format(self.image.width(),
                                                      self.image.height()))
            self.updateStatus("Created new image")


    def fileOpen(self):
        if not self.okToContinue():
            return
        dir = (os.path.dirname(self.filename)
               if self.filename is not None else ".")
        formats = (["*.{0}".format(unicode(format).lower())
                for format in QImageReader.supportedImageFormats()])
        fname = unicode(QFileDialog.getOpenFileName(self,
                "Image Changer - Choose Image", dir,
                "Image files ({0})".format(" ".join(formats))))
        if fname:
            self.loadFile(fname)


    def loadFile(self, fname=None):
        if fname is None:
            action = self.sender()
            if isinstance(action, QAction):
                fname = unicode(action.data().toString())
                if not self.okToContinue():
                    return
            else:
                return
        if fname:
            self.filename = None
            image = QImage(fname)
            if image.isNull():
                message = "Failed to read {0}".format(fname)
            else:
                self.addRecentFile(fname)
                self.image = QImage()
                for action, check in self.resetableActions:
                    action.setChecked(check)
                self.image = image
                self.filename = fname
                self.showImage()
                self.dirty = False
                self.sizeLabel.setText("{0} x {1}".format(
                                       image.width(), image.height()))
                message = "Loaded {0}".format(os.path.basename(fname))
            self.updateStatus(message)


    def addRecentFile(self, fname):
        if fname is None:
            return
        if not self.recentFiles.contains(fname):
            self.recentFiles.prepend(QString(fname))
            while self.recentFiles.count() > 9:
                self.recentFiles.takeLast()


    def fileSave(self):
        if self.image.isNull():
            return True
        if self.filename is None:
            return self.fileSaveAs()
        else:
            if self.image.save(self.filename, None):
                self.updateStatus("Saved as {0}".format(self.filename))
                self.dirty = False
                return True
            else:
                self.updateStatus("Failed to save {0}".format(
                                  self.filename))
                return False


    def fileSaveAs(self):
        if self.image.isNull():
            return True
        fname = self.filename if self.filename is not None else "."
        formats = (["*.{0}".format(unicode(format).lower())
                for format in QImageWriter.supportedImageFormats()])
        fname = unicode(QFileDialog.getSaveFileName(self,
                "Image Changer - Save Image", fname,
                "Image files ({0})".format(" ".join(formats))))
        if fname:
            if "." not in fname:
                fname += ".png"
            self.addRecentFile(fname)
            self.filename = fname
            return self.fileSave()
        return False


    def filePrint(self):
        if self.image.isNull():
            return
        if self.printer is None:
            self.printer = QPrinter(QPrinter.HighResolution)
            self.printer.setPageSize(QPrinter.Letter)
        form = QPrintDialog(self.printer, self)
        if form.exec_():
            painter = QPainter(self.printer)
            rect = painter.viewport()
            size = self.image.size()
            size.scale(rect.size(), Qt.KeepAspectRatio)
            painter.setViewport(rect.x(), rect.y(), size.width(),
                                size.height())
            painter.drawImage(0, 0, self.image)


    def editInvert(self, on):
        if self.image.isNull():
            return
        self.image.invertPixels()
        self.showImage()
        self.dirty = True
        self.updateStatus("Inverted" if on else "Uninverted")


    def editSwapRedAndBlue(self, on):
        if self.image.isNull():
            return
        self.image = self.image.rgbSwapped()
        self.showImage()
        self.dirty = True
        self.updateStatus(("Swapped Red and Blue"
                           if on else "Unswapped Red and Blue"))


    def editUnMirror(self, on):
        if self.image.isNull():
            return
        if self.mirroredhorizontally:
            self.editMirrorHorizontal(False)
        if self.mirroredvertically:
            self.editMirrorVertical(False)


    def editMirrorHorizontal(self, on):
        if self.image.isNull():
            return
        self.image = self.image.mirrored(True, False)
        self.showImage()
        self.mirroredhorizontally = not self.mirroredhorizontally
        self.dirty = True
        self.updateStatus(("Mirrored Horizontally"
                           if on else "Unmirrored Horizontally"))


    def editMirrorVertical(self, on):
        if self.image.isNull():
            return
        self.image = self.image.mirrored(False, True)
        self.showImage()
        self.mirroredvertically = not self.mirroredvertically
        self.dirty = True
        self.updateStatus(("Mirrored Vertically"
                           if on else "Unmirrored Vertically"))


    def editZoom(self):
        if self.image.isNull():
            return
        percent, ok = QInputDialog.getInteger(self,
                "Image Changer - Zoom", "Percent:",
                self.zoomSpinBox.value(), 1, 400)
        if ok:
            self.zoomSpinBox.setValue(percent)


    def editResize(self):
        if self.image.isNull():
            return
        form = resizedlg.ResizeDlg(self.image.width(),
                                   self.image.height(), self)
        if form.exec_():
            width, height = form.result()
            if (width == self.image.width() and
                height == self.image.height()):
                self.statusBar().showMessage("Resized to the same size",
                                             5000)
            else:
                self.image = self.image.scaled(width, height)
                self.showImage()
                self.dirty = True
                size = "{0} x {1}".format(self.image.width(),
                                          self.image.height())
                self.sizeLabel.setText(size)
                self.updateStatus("Resized to {0}".format(size))


    def showImage(self, percent=None):
        if self.image.isNull():
            return
        if percent is None:
            percent = self.zoomSpinBox.value()
        factor = percent / 100.0
        width = self.image.width() * factor
        height = self.image.height() * factor
        image = self.image.scaled(width, height, Qt.KeepAspectRatio)
        self.imageLabel.setPixmap(QPixmap.fromImage(image))


    def helpAbout(self):
        QMessageBox.about(self, "About Image Changer",
                """<b>Image Changer</b> v {0}
                <p>Copyright &copy; 2008 Qtrac Ltd. 
                All rights reserved.
                <p>This application can be used to perform
                simple image manipulations.
                <p>Python {1} - Qt {2} - PyQt {3} on {4}""".format(
                __version__, platform.python_version(),
                QT_VERSION_STR, PYQT_VERSION_STR,
                platform.system()))


    def helpHelp(self):
        form = helpform.HelpForm("index.html", self)
        form.show()
Example #5
0
 def createWidget(self, parent):
     w = QSpinBox(parent, buttonSymbols=QSpinBox.NoButtons)
     w.setFocusPolicy(Qt.ClickFocus)
     w.valueChanged[int].connect(self.slotValueChanged)
     return w