Exemplo n.º 1
0
    def _delete(self):
        index_list = []
        for model_index in self.tableView.selectionModel().selectedRows():
            index = QPersistentModelIndex(model_index)
            index_list.append(index)

        for index in index_list:
            self.model.removeRow(index.row())
            self._remove_project_from_config(index.data())

        if index_list:
            self.dirty = True
Exemplo n.º 2
0
def test_model_persistent_index(model_test):
    '''
    ☑ 🛇 read-only.ro
    ☑ ★ user.json
    ☑ ⎕ commands.json
    ☐ 🛇 asset:plover:assets/main.json
    '''
    persistent_index = QPersistentModelIndex(model_test.model.index(1))
    assert persistent_index.row() == 1
    assert persistent_index.data(Qt.CheckStateRole) == Qt.Checked
    assert persistent_index.data(Qt.DecorationRole) == 'favorite'
    assert persistent_index.data(Qt.DisplayRole) == 'user.json'
    model_test.configure(classic_dictionaries_display_order=True)
    assert persistent_index.row() == 2
    assert persistent_index.data(Qt.CheckStateRole) == Qt.Checked
    assert persistent_index.data(Qt.DecorationRole) == 'favorite'
    assert persistent_index.data(Qt.DisplayRole) == 'user.json'
    model_test.model.setData(persistent_index, Qt.Unchecked, Qt.CheckStateRole)
    assert persistent_index.row() == 2
    assert persistent_index.data(Qt.CheckStateRole) == Qt.Unchecked
    assert persistent_index.data(Qt.DecorationRole) == 'normal'
    assert persistent_index.data(Qt.DisplayRole) == 'user.json'
Exemplo n.º 3
0
class Viewer(QtMainWindow):
    jobAdded = Signal()
    jobFinished = Signal()

    def __init__(self, weboob, parent=None):
        super(Viewer, self).__init__(parent)

        self.ui = Ui_Viewer()
        self.ui.setupUi(self)
        self.ui.prevButton.clicked.connect(self.prev)
        self.ui.nextButton.clicked.connect(self.next)
        self.ui.firstButton.clicked.connect(self.first)
        self.ui.lastButton.clicked.connect(self.last)
        self.ui.actionZoomIn.triggered.connect(self.zoomIn)
        self.ui.actionZoomOut.triggered.connect(self.zoomOut)
        self.ui.actionFullSize.triggered.connect(self.zoomFullSize)
        self.ui.actionFitWindow.triggered.connect(self.zoomFit)

        self.ui.actionSaveImage.setShortcut(QKeySequence.Save)
        self.ui.actionSaveImage.triggered.connect(self.saveImage)
        self.ui.actionClose.setShortcut(QKeySequence.Close)
        self.ui.actionClose.triggered.connect(self.close)

        self.model = None
        self.current = None
        self.total = 0
        self.zoomFactor = 1
        self.zoomMode = ZOOM_FACTOR
        self.weboob = weboob

    def setData(self, model, qidx):
        self.model = model
        self.current = QPersistentModelIndex(qidx)

        self.model.rowsInserted.connect(self.updatePos)
        self.model.rowsRemoved.connect(self.updatePos)
        self.model.rowsInserted.connect(self.updateNavButtons)
        self.model.rowsRemoved.connect(self.updateNavButtons)
        self.model.dataChanged.connect(self._dataChanged)
        self.model.modelReset.connect(self.disable)

        self.updateImage()

    @Slot()
    def disable(self):
        self.setEnabled(False)

    def updateNavButtons(self):
        prev = self.current.row() > 0
        self.ui.prevButton.setEnabled(prev)
        self.ui.firstButton.setEnabled(prev)
        next = self.current.row() < self.total - 1
        self.ui.nextButton.setEnabled(next)
        self.ui.lastButton.setEnabled(next)

    def updatePos(self):
        self.total = self.model.rowCount(self.current.parent())
        self.ui.posLabel.setText('%d / %d' % (self.current.row() + 1, self.total))

    def updateImage(self):
        self.updatePos()
        self.updateNavButtons()

        obj = self.current.data(ResultModel.RoleObject)

        if obj.data is NotLoaded:
            self.model.fillObj(obj, ['data'], QModelIndex(self.current))
            self.pixmap = None
        elif obj.data:
            self.pixmap = QPixmap(QImage.fromData(obj.data))
        else:
            self.pixmap = QPixmap()

        self._rebuildImage()

    @Slot(QModelIndex)
    def _dataChanged(self, qidx):
        if qidx == self.current:
            obj = qidx.data(ResultModel.RoleObject)

            if obj.data:
                self.pixmap = QPixmap(QImage.fromData(obj.data))
            else:
                self.pixmap = QPixmap()
            self._rebuildImage()

    @Slot()
    def next(self):
        new = self.current.sibling(self.current.row() + 1, 0)
        if not new.isValid():
            return
        self.current = QPersistentModelIndex(new)
        self.updateImage()

    @Slot()
    def prev(self):
        if self.current.row() == 0:
            return
        self.current = QPersistentModelIndex(self.current.sibling(self.current.row() - 1, 0))
        self.updateImage()

    @Slot()
    def first(self):
        self.current = QPersistentModelIndex(self.current.sibling(0, 0))
        self.updateImage()

    @Slot()
    def last(self):
        self.current = QPersistentModelIndex(self.current.sibling(self.total - 1, 0))
        self.updateImage()

    @Slot()
    def zoomIn(self):
        self.zoomFactor *= 1.25
        self.zoomMode = ZOOM_FACTOR
        self._rebuildImage()

    @Slot()
    def zoomOut(self):
        self.zoomFactor *= 0.75
        self.zoomMode = ZOOM_FACTOR
        self._rebuildImage()

    @Slot()
    def zoomFullSize(self):
        self.zoomFactor = 1
        self.zoomMode = ZOOM_FACTOR
        self._rebuildImage()

    @Slot()
    def zoomFit(self):
        self.zoomMode = ZOOM_FIT
        self._rebuildImage()

    def resizeEvent(self, ev):
        super(Viewer, self).resizeEvent(ev)
        if self.zoomMode == ZOOM_FIT:
            self._rebuildImage()

    def _rebuildZoom(self):
        if self.zoomMode == ZOOM_FACTOR:
            new_width = int(self.pixmap.width() * self.zoomFactor)
            pixmap = self.pixmap.scaledToWidth(new_width, Qt.SmoothTransformation)
        else:
            new_size = self.ui.scrollArea.viewport().size()
            pixmap = self.pixmap.scaled(new_size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
            self.zoomFactor = pixmap.width() / float(self.pixmap.width())
        return pixmap

    def _rebuildImage(self):
        if self.pixmap is None:
            self.ui.view.setText('Loading...')
            return
        elif self.pixmap.isNull():
            self.ui.view.setText('Image could not be loaded')
            return

        pixmap = self._rebuildZoom()
        self.ui.view.setPixmap(pixmap)

    @Slot()
    def saveImage(self):
        def ext_for_filter(s):
            return re.match(r'(?:[A-Z]+) \(\*\.([a-z]+)\)$', s).group(1)

        if not self.pixmap:
            return

        filters = ['PNG (*.png)', 'JPEG (*.jpg)', 'GIF (*.gif)']

        obj = self.current.data(ResultModel.RoleObject)
        name = '%s.%s' % (obj.title or obj.id or u'', obj.ext or 'png')
        default = filters[0]
        for f in filters:
            if name.endswith(ext_for_filter(f)):
                default = f
        filters = ';;'.join(filters)

        target = os.path.join(self.parent().lastSaveDir, name)
        out, filter = QFileDialog.getSaveFileName(self, 'Save image', target, filters, default)
        if not out:
            return

        ext = ext_for_filter(filter)

        self.parent().lastSaveDir = os.path.dirname(out)
        if not os.path.splitext(out)[1]:
            out = '%s.%s' % (out, ext)

            if os.path.exists(out):
                q = self.tr('%s already exists, are you sure you want to replace it?') % out
                reply = QMessageBox.question(self, self.tr('Overwrite?'), q)
                if reply == QMessageBox.No:
                    return self.saveImage()

        self.pixmap.save(out, ext.upper())
Exemplo n.º 4
0
class Tab(QWidget):
    currItemChanged = pyqtSignal(['QModelIndex'])

    def __init__(self, packItem=QModelIndex(), parent: TabWidget = None):
        super(Tab, self).__init__(parent)
        self.tabWidget = parent
        self.icon = QIcon()
        self.initActions()

        self.pathToolBar = ToolBar(self)
        self.pathToolBar.addAction(self.backAct)
        self.pathToolBar.addAction(self.forwardAct)

        self.pathLine: AddressLine = AddressLine(self)
        self.objTypeLine = LineEdit(self, placeholderText="Object Type")
        self.objTypeLine.setFixedWidth(168)
        self.objTypeLine.setReadOnly(True)

        self.descrLabel = QLabel(self)
        self.descrLabel.setWordWrap(True)
        self.descrLabel.setTextInteractionFlags(Qt.TextSelectableByMouse)

        QWebEngineSettings.defaultSettings().setAttribute(
            QWebEngineSettings.PluginsEnabled, True)
        self.mediaWidget = QWebEngineView()
        self.saveMediaAsBtn = QPushButton(
            f"Save media as..",
            self,
            toolTip="Save media file as..",
            clicked=lambda: self.saveMediaAsWithDialog(
                QStandardPaths.writableLocation(QStandardPaths.
                                                DocumentsLocation)))
        self.saveMediaBtn = QPushButton(
            f"Save media on desktop",
            self,
            toolTip="Save media file on desktop",
            clicked=lambda: self.saveMediaAsWithDialog(
                QStandardPaths.writableLocation(QStandardPaths.DesktopLocation)
            ))
        self.mediaViewWidget = QWidget()
        mediaViewWidgetLayout = QVBoxLayout(self.mediaViewWidget)
        mediaViewWidgetLayout.setContentsMargins(0, 0, 0, 0)
        mediaViewWidgetLayout.addWidget(self.mediaWidget)
        mediaViewWidgetLayout.addWidget(self.saveMediaBtn)
        mediaViewWidgetLayout.addWidget(self.saveMediaAsBtn)
        self.mediaViewWidget.hide()

        self.attrsTreeView = AttrsTreeView(self)
        self.attrsTreeView.setFrameShape(QFrame.NoFrame)

        self.toolBar = ToolBar(self)
        self.toolBar.addAction(self.attrsTreeView.zoomInAct)
        self.toolBar.addAction(self.attrsTreeView.zoomOutAct)
        self.toolBar.addAction(self.attrsTreeView.collapseAllAct)
        self.toolBar.addAction(self.attrsTreeView.expandAllAct)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.attrsTreeView.undoAct)
        self.toolBar.addAction(self.attrsTreeView.redoAct)
        self.toolBar.addAction(self.attrsTreeView.copyAct)
        self.toolBar.addAction(self.attrsTreeView.cutAct)
        self.toolBar.addAction(self.attrsTreeView.pasteAct)
        self.toolBar.addAction(self.attrsTreeView.delClearAct)
        self.toolBar.addAction(self.attrsTreeView.editCreateInDialogAct)
        self.toolBar.addAction(self.attrsTreeView.addAct)
        self.searchBar = SearchBar(
            self.attrsTreeView,
            parent=self,
            filterColumns=[ATTRIBUTE_COLUMN, VALUE_COLUMN],
            closable=True)
        self.searchBar.hide()
        self.openSearchBarSC = QShortcut(SC_SEARCH,
                                         self,
                                         activated=self.openSearchBar)

        self.packItem = QPersistentModelIndex(QModelIndex())
        self.prevItems = []
        self.nextItems = []
        if packItem.isValid():
            self.openItem(packItem)
        else:
            self.openEmptyItem()

        self._initLayout()

    # noinspection PyArgumentList
    def initActions(self):
        self.backAct = QAction(BACK_ICON,
                               "Back",
                               self,
                               statusTip=f"Go back one item",
                               toolTip=f"Go back one item",
                               shortcut=SC_BACK,
                               triggered=self.openPrevItem,
                               enabled=False)

        self.forwardAct = QAction(FORWARD_ICON,
                                  "Forward",
                                  self,
                                  statusTip=f"Go forward one item",
                                  toolTip=f"Go forward one item",
                                  shortcut=SC_FORWARD,
                                  triggered=self.openNextItem,
                                  enabled=False)

    def windowTitle(self) -> str:
        return self.packItem.data(NAME_ROLE)

    def windowIcon(self) -> QIcon:
        return self.packItem.data(Qt.DecorationRole)

    def openSearchBar(self):
        self.searchBar.show()
        self.searchBar.searchLine.setFocus()

    def openItem(self, packItem: QModelIndex):
        if not packItem == QModelIndex(self.packItem):
            self.nextItems.clear()
            if self.packItem.isValid():
                self.prevItems.append(self.packItem)
            self._openItem(packItem)

    def openPrevItem(self):
        if self.prevItems:
            prevItem = self.prevItems.pop()
            self.nextItems.append(self.packItem)
            self._openItem(QModelIndex(prevItem))

    def openNextItem(self):
        if self.nextItems:
            nextItem = self.nextItems.pop()
            self.prevItems.append(self.packItem)
            self._openItem(QModelIndex(nextItem))

    def openEmptyItem(self):
        self._openItem(QModelIndex())

    def _openItem(self, packItem: QModelIndex):
        try:
            currTab: Tab = self.tabWidget.currentWidget()
            state = currTab.attrsTreeView.header().saveState()
        except AttributeError:
            # if there is no curr widget, there is no current header state, it
            state = None

        self.packItem = QPersistentModelIndex(packItem.siblingAtColumn(0))
        self.descrLabel.setText("")

        self.packItemObj = self.packItem.data(OBJECT_ROLE)
        self.updateMediaWidget()
        self.pathLine.setText(getTreeItemPath(self.packItem))
        self.objTypeLine.setText(getTypeName(type(self.packItemObj)))

        icon = self.packItem.data(Qt.DecorationRole)
        if icon:
            self.setWindowIcon(icon)
        self.setWindowTitle(self.packItem.data(Qt.DisplayRole))
        self.attrsTreeView.newPackItem(self.packItem)
        self.attrsTreeView.selectionModel().currentChanged.connect(
            self.showDetailInfoItemDoc)
        self.currItemChanged.emit(QModelIndex(self.packItem))

        self.forwardAct.setEnabled(
            True) if self.nextItems else self.forwardAct.setDisabled(True)
        self.backAct.setEnabled(
            True) if self.prevItems else self.backAct.setDisabled(True)
        if state:
            self.attrsTreeView.header().restoreState(state)

    def updateMediaWidget(self):
        if self.packItem.data(IS_MEDIA_ROLE):
            self.mediaWidget.setContent(b"loading...")
            self.mediaViewWidget.show()
            if not self.mediaWidget.width():
                # set equal sizes
                oldSizes = self.splitter.sizes()
                newSizes = [
                    sum(oldSizes) / (len(oldSizes)) for size in oldSizes
                ]
                self.splitter.setSizes(newSizes)

            try:
                mediaContent = self.packItem.data(MEDIA_CONTENT_ROLE)
                if self.packItem.data(IS_URL_MEDIA_ROLE):
                    self.mediaWidget.load(QUrl(mediaContent.value))
                else:
                    self.mediaWidget.setContent(mediaContent.value,
                                                mediaContent.mime_type)
            except Exception as e:
                print(e)
                self.mediaWidget.setContent(
                    b"Error occurred while loading media")
            self.mediaWidget.setZoomFactor(1.0)
        else:
            self.mediaViewWidget.hide()

    def saveMediaAsWithDialog(self, directory="") -> bool:
        mediaContent = self.packItem.data(MEDIA_CONTENT_ROLE)
        file = self.packItem.data(NAME_ROLE)
        saved = False
        while not saved:
            try:
                file = QFileDialog.getSaveFileName(
                    self,
                    'Save media File',
                    directory + "/" + file.strip("/"),
                    options=FILE_DIALOG_OPTIONS)[0]
            except AttributeError as e:
                QMessageBox.critical(self, "Error", f"{e}")
            else:
                if file:
                    saved = self.saveMedia(mediaContent, file)
                else:
                    # cancel pressed
                    return

    def saveMedia(self, media=None, file: str = None) -> bool:
        try:
            with open(file, "wb") as f:
                f.write(media.value)
            return True
        except (TypeError, ValueError) as e:
            QMessageBox.critical(self, "Error",
                                 f"Media couldn't be saved: {file}: {e}")
        except AttributeError as e:
            QMessageBox.critical(self, "Error",
                                 f"No chosen media to save: {e}")
        return False

    def showDetailInfoItemDoc(self, detailInfoItem: QModelIndex):
        self.descrLabel.setText(detailInfoItem.data(Qt.WhatsThisRole))

    def _initLayout(self):
        pathWidget = QWidget()
        pathLayout = QHBoxLayout(pathWidget)
        pathLayout.setContentsMargins(0, 0, 0, 0)
        pathLayout.addWidget(self.pathToolBar)
        pathLayout.addWidget(self.pathLine)
        pathLayout.addWidget(self.objTypeLine)
        pathWidget.setFixedHeight(TOOLBARS_HEIGHT)

        toolBarWidget = QWidget()
        toolBarLayout = QHBoxLayout(toolBarWidget)
        toolBarLayout.setContentsMargins(0, 0, 0, 0)
        toolBarLayout.addWidget(self.toolBar)
        toolBarLayout.addWidget(self.searchBar)
        toolBarWidget.setFixedHeight(TOOLBARS_HEIGHT)

        treeViewWidget = QWidget()
        treeViewLayout = QVBoxLayout(treeViewWidget)
        treeViewLayout.setContentsMargins(0, 0, 0, 0)
        treeViewLayout.addWidget(pathWidget)
        treeViewLayout.addWidget(self.attrsTreeView)
        treeViewLayout.addWidget(self.descrLabel)

        self.splitter = QSplitter()
        self.splitter.setOrientation(Qt.Horizontal)
        self.splitter.setContentsMargins(0, 0, 0, 0)
        self.splitter.addWidget(treeViewWidget)
        self.splitter.addWidget(self.mediaViewWidget)

        layout = QVBoxLayout(self)
        layout.setObjectName("tabLayout")
        layout.addWidget(pathWidget)
        layout.addWidget(toolBarWidget)
        layout.addWidget(self.splitter)
        layout.setSpacing(2)
        layout.setContentsMargins(0, 2, 0, 2)
Exemplo n.º 5
0
class Viewer(QtMainWindow):
    jobAdded = Signal()
    jobFinished = Signal()

    def __init__(self, weboob, parent=None):
        super(Viewer, self).__init__(parent)

        self.ui = Ui_Viewer()
        self.ui.setupUi(self)
        self.ui.prevButton.clicked.connect(self.prev)
        self.ui.nextButton.clicked.connect(self.next)
        self.ui.firstButton.clicked.connect(self.first)
        self.ui.lastButton.clicked.connect(self.last)
        self.ui.actionZoomIn.triggered.connect(self.zoomIn)
        self.ui.actionZoomOut.triggered.connect(self.zoomOut)
        self.ui.actionFullSize.triggered.connect(self.zoomFullSize)
        self.ui.actionFitWindow.triggered.connect(self.zoomFit)

        self.ui.actionSaveImage.setShortcut(QKeySequence.Save)
        self.ui.actionSaveImage.triggered.connect(self.saveImage)
        self.ui.actionClose.setShortcut(QKeySequence.Close)
        self.ui.actionClose.triggered.connect(self.close)

        self.model = None
        self.current = None
        self.total = 0
        self.zoomFactor = 1
        self.zoomMode = ZOOM_FACTOR
        self.weboob = weboob

    def setData(self, model, qidx):
        self.model = model
        self.current = QPersistentModelIndex(qidx)

        self.model.rowsInserted.connect(self.updatePos)
        self.model.rowsRemoved.connect(self.updatePos)
        self.model.rowsInserted.connect(self.updateNavButtons)
        self.model.rowsRemoved.connect(self.updateNavButtons)
        self.model.dataChanged.connect(self._dataChanged)
        self.model.modelReset.connect(self.disable)

        self.updateImage()

    @Slot()
    def disable(self):
        self.setEnabled(False)

    def updateNavButtons(self):
        prev = self.current.row() > 0
        self.ui.prevButton.setEnabled(prev)
        self.ui.firstButton.setEnabled(prev)
        next = self.current.row() < self.total - 1
        self.ui.nextButton.setEnabled(next)
        self.ui.lastButton.setEnabled(next)

    def updatePos(self):
        self.total = self.model.rowCount(self.current.parent())
        self.ui.posLabel.setText('%d / %d' %
                                 (self.current.row() + 1, self.total))

    def updateImage(self):
        self.updatePos()
        self.updateNavButtons()

        obj = self.current.data(ResultModel.RoleObject)

        if obj.data is NotLoaded:
            self.model.fillObj(obj, ['data'], QModelIndex(self.current))
            self.pixmap = None
        elif obj.data:
            self.pixmap = QPixmap(QImage.fromData(obj.data))
        else:
            self.pixmap = QPixmap()

        self._rebuildImage()

    @Slot(QModelIndex)
    def _dataChanged(self, qidx):
        if qidx == self.current:
            obj = qidx.data(ResultModel.RoleObject)

            if obj.data:
                self.pixmap = QPixmap(QImage.fromData(obj.data))
            else:
                self.pixmap = QPixmap()
            self._rebuildImage()

    @Slot()
    def next(self):
        new = self.current.sibling(self.current.row() + 1, 0)
        if not new.isValid():
            return
        self.current = QPersistentModelIndex(new)
        self.updateImage()

    @Slot()
    def prev(self):
        if self.current.row() == 0:
            return
        self.current = QPersistentModelIndex(
            self.current.sibling(self.current.row() - 1, 0))
        self.updateImage()

    @Slot()
    def first(self):
        self.current = QPersistentModelIndex(self.current.sibling(0, 0))
        self.updateImage()

    @Slot()
    def last(self):
        self.current = QPersistentModelIndex(
            self.current.sibling(self.total - 1, 0))
        self.updateImage()

    @Slot()
    def zoomIn(self):
        self.zoomFactor *= 1.25
        self.zoomMode = ZOOM_FACTOR
        self._rebuildImage()

    @Slot()
    def zoomOut(self):
        self.zoomFactor *= 0.75
        self.zoomMode = ZOOM_FACTOR
        self._rebuildImage()

    @Slot()
    def zoomFullSize(self):
        self.zoomFactor = 1
        self.zoomMode = ZOOM_FACTOR
        self._rebuildImage()

    @Slot()
    def zoomFit(self):
        self.zoomMode = ZOOM_FIT
        self._rebuildImage()

    def resizeEvent(self, ev):
        super(Viewer, self).resizeEvent(ev)
        if self.zoomMode == ZOOM_FIT:
            self._rebuildImage()

    def _rebuildZoom(self):
        if self.zoomMode == ZOOM_FACTOR:
            new_width = int(self.pixmap.width() * self.zoomFactor)
            pixmap = self.pixmap.scaledToWidth(new_width,
                                               Qt.SmoothTransformation)
        else:
            new_size = self.ui.scrollArea.viewport().size()
            pixmap = self.pixmap.scaled(new_size, Qt.KeepAspectRatio,
                                        Qt.SmoothTransformation)
            self.zoomFactor = pixmap.width() / float(self.pixmap.width())
        return pixmap

    def _rebuildImage(self):
        if self.pixmap is None:
            self.ui.view.setText('Loading...')
            return
        elif self.pixmap.isNull():
            self.ui.view.setText('Image could not be loaded')
            return

        pixmap = self._rebuildZoom()
        self.ui.view.setPixmap(pixmap)

    @Slot()
    def saveImage(self):
        def ext_for_filter(s):
            return re.match(r'(?:[A-Z]+) \(\*\.([a-z]+)\)$', s).group(1)

        if not self.pixmap:
            return

        filters = ['PNG (*.png)', 'JPEG (*.jpg)', 'GIF (*.gif)']

        obj = self.current.data(ResultModel.RoleObject)
        name = '%s.%s' % (obj.title or obj.id or u'', obj.ext or 'png')
        default = filters[0]
        for f in filters:
            if name.endswith(ext_for_filter(f)):
                default = f
        filters = ';;'.join(filters)

        target = os.path.join(self.parent().lastSaveDir, name)
        out, filter = QFileDialog.getSaveFileName(self, 'Save image', target,
                                                  filters, default)
        if not out:
            return

        ext = ext_for_filter(filter)

        self.parent().lastSaveDir = os.path.dirname(out)
        if not os.path.splitext(out)[1]:
            out = '%s.%s' % (out, ext)

            if os.path.exists(out):
                q = self.tr(
                    '%s already exists, are you sure you want to replace it?'
                ) % out
                reply = QMessageBox.question(self, self.tr('Overwrite?'), q)
                if reply == QMessageBox.No:
                    return self.saveImage()

        self.pixmap.save(out, ext.upper())