Ejemplo n.º 1
0
class DocumentViewManager(QMainWindow):
    """
    MDI area for displaying supporting documents within a given context e.g.
    supporting documents for a specific household based on the lifetime of the
    'SourceDocumentManager' instance.
    """
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setWindowFlags(Qt.Window)

        self._mdi_area = QMdiArea()
        self._mdi_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self._mdi_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.setCentralWidget(self._mdi_area)
        # set the size of mid_area and DocumentViewManager based on the
        # screen size.
        screen = QDesktopWidget().availableGeometry()
        self._mdi_area.resize(screen.width() - 30, screen.height() - 80)
        self.resize(self._mdi_area.size())
        self._mdi_area.subWindowActivated.connect(self.update_actions)
        self._viewer_mapper = QSignalMapper(self)
        self._viewer_mapper.mapped[QWidget].connect(self.set_active_sub_window)

        win_title = QApplication.translate(
            "DocumentViewManager",
            "Document Viewer"
        )
        self.setWindowTitle(win_title)
        self.setUnifiedTitleAndToolBarOnMac(True)
        self.statusBar().showMessage(
            QApplication.translate(
                "DocumentViewManager",
                "Ready"
            )
        )
        self._doc_viewers = {}

        self._create_menu_actions()
        self.update_actions()

    def center(self):
        """
        Move the Document viewer to the center of the screen.
        """
        # Get the current screens' dimensions...
        screen = QDesktopWidget().availableGeometry()
        # ... and get this windows' dimensions
        mdi_area_size = self.frameGeometry()
        # The horizontal position
        hpos = (screen.width() - mdi_area_size.width()) / 2
        # vertical position
        vpos = (screen.height() - mdi_area_size.height()) / 2
        # repositions the window
        self.move(hpos, vpos)

    def _create_menu_actions(self):
        self._window_menu = self.menuBar().addMenu(
            QApplication.translate(
                "DocumentViewManager","&Windows"))

        self._close_act = QAction(
            QApplication.translate("DocumentViewManager",
                                                         "Cl&ose"), self)
        self._close_act.setStatusTip(
            QApplication.translate("DocumentViewManager",
                                   "Close the active document viewer"))
        self._close_act.triggered.connect(self._mdi_area.closeActiveSubWindow)

        self._close_all_act = QAction(QApplication.translate(
            "DocumentViewManager",
            "Close &All"), self
        )
        self._close_all_act.setStatusTip(
            QApplication.translate("DocumentViewManager",
                                   "Close all the document viewers")
        )
        self._close_all_act.triggered.connect(
            self._mdi_area.closeAllSubWindows
        )

        self._tile_act = QAction(QApplication.translate(
            "DocumentViewManager",
            "&Tile"), self
        )
        self._tile_act.setStatusTip(
            QApplication.translate("DocumentViewManager",
                                   "Tile the document viewers"))
        self._tile_act.triggered.connect(self.tile_windows)

        self._cascade_act = QAction(QApplication.translate(
            "DocumentViewManager",
            "&Cascade"), self)
        self._cascade_act.setStatusTip(QApplication.translate(
            "DocumentViewManager",
            "Cascade the document viewers"))
        self._cascade_act.triggered.connect(self.cascade_windows)

        self._next_act = QAction(QApplication.translate(
            "DocumentViewManager",
            "Ne&xt"), self)
        self._next_act.setStatusTip(
            QApplication.translate(
                "DocumentViewManager",
                "Move the focus to the next document viewer"
            )
        )
        self._next_act.triggered.connect(self._mdi_area.activateNextSubWindow)

        self._previous_act = QAction(QApplication.translate(
            "DocumentViewManager",
            "Pre&vious"), self)
        self._previous_act.setStatusTip(
            QApplication.translate(
                "DocumentViewManager",
                "Move the focus to the previous document viewer"
            )
        )
        self._previous_act.triggered.connect(
            self._mdi_area.activatePreviousSubWindow
        )

        self._separator_act = QAction(self)
        self._separator_act.setSeparator(True)

        self.update_window_menu()
        self._window_menu.aboutToShow.connect(self.update_window_menu)

    def cascade_windows(self):
        #Cascade document windows
        self._mdi_area.cascadeSubWindows()

    def tile_windows(self):
        #Arrange document windows to occupy the available space in mdi area
        self._mdi_area.tileSubWindows()

    def update_actions(self):
        if self._mdi_area.activeSubWindow():
            has_mdi_child = True

        else:
            has_mdi_child = False

        self._close_act.setEnabled(has_mdi_child)
        self._close_all_act.setEnabled(has_mdi_child)
        self._tile_act.setEnabled(has_mdi_child)
        self._cascade_act.setEnabled(has_mdi_child)
        self._previous_act.setEnabled(has_mdi_child)
        self._next_act.setEnabled(has_mdi_child)
        self._separator_act.setVisible(has_mdi_child)

    def update_window_menu(self):
        self._window_menu.clear()
        self._window_menu.addAction(self._close_act)
        self._window_menu.addAction(self._close_all_act)
        self._window_menu.addSeparator()
        self._window_menu.addAction(self._tile_act)
        self._window_menu.addAction(self._cascade_act)
        self._window_menu.addSeparator()
        self._window_menu.addAction(self._next_act)
        self._window_menu.addAction(self._previous_act)
        self._window_menu.addAction(self._separator_act)

        windows = self._mdi_area.subWindowList()
        self._separator_act.setVisible(len(windows) != 0)

        for i, window in enumerate(windows):
            text = "%d. %s" % (i + 1, window.windowTitle())

            win_action = self._window_menu.addAction(text)
            win_action.setCheckable(True)
            win_action.setChecked(window is self._mdi_area.activeSubWindow())
            win_action.triggered.connect(self._viewer_mapper.map)
            self._viewer_mapper.setMapping(win_action, window)

    def load_viewer(self, document_widget, visible=True):
        """
        Open a new instance of the viewer or activate an existing one if the
        document had been previously loaded.
        :param document_widget: Contains all the necessary information required
        to load the specific document.
        :type document_widget: DocumentWidget
        :param visible: True to show the view manager after the viewer has
        been loaded, otherwise it will be the responsibility of the caller to
        enable visibility.
        :type visible: bool
        :returns: True if the document was successfully loaded, else False.
        :rtype: bool
        """
        doc_identifier = document_widget.file_identifier()

        if doc_identifier in self._doc_viewers:

            doc_sw = self._doc_viewers[doc_identifier]

            self._mdi_area.setActiveSubWindow(doc_sw)
            doc_sw.showNormal()

        else:
            doc_viewer = self._create_viewer(document_widget)

            abs_doc_path = self.absolute_document_path(document_widget)

            if not QFile.exists(abs_doc_path):
                msg = QApplication.translate(
                    "DocumentViewManager",
                    "The selected document does not exist."
                    "\nPlease check the supporting documents' "
                    "repository setting."
                )
                QMessageBox.critical(
                    self,
                    QApplication.translate(
                        "DocumentViewManager","Invalid Document"
                    ),
                    msg
                )

                return False

            doc_viewer.load_document(abs_doc_path)

            self._doc_viewers[doc_identifier] = doc_viewer

            self._mdi_area.addSubWindow(doc_viewer)

            doc_viewer.show()

        if not self.isVisible() and visible:
            self.setVisible(True)

        if self.isMinimized():
            self.showNormal()

        self.center()

        return True

    def set_active_sub_window(self, viewer):
        if viewer:
            self._mdi_area.setActiveSubWindow(viewer)

    def absolute_document_path(self, document_widget):
        """
        Build the absolute document path using info from the document widget.
        :param document_widget: Instance of document widget.
        :return: Absolute path of the supporting document.
        :rtype: str
        """
        abs_path = ''

        file_manager = document_widget.fileManager
        if not file_manager is None:
            network_repository = file_manager.networkPath
            file_id = document_widget.file_identifier()
            source_entity = document_widget.doc_source_entity()
            profile_name = current_profile().name
            doc_type = document_widget.doc_type_value().lower().replace(
                ' ', '_'
            )
            file_name, file_extension = guess_extension(
                document_widget.displayName()
            )

            abs_path = network_repository + "/" +profile_name + '/' +\
                       unicode(source_entity) + "/" + unicode(doc_type) + "/" +\
                       unicode(file_id) + unicode(file_extension)

        return abs_path

    def reset(self):
        """
        Removes all document viewers in the view area.
        The QCloseEvent sent to each sub-window will decrement the register.
        """
        self._mdi_area.closeAllSubWindows()

    def _create_viewer(self, document_widget):
        """
        Creates a new instance of a document viewer.
        :param document_widget: Contains all
        the necessary information required
        to load the specific document.
        :return: Document viewer object
        :rtype: DocumentViewer
        """
        doc_viewer = DocumentViewer(
            self._mdi_area, document_widget.file_identifier()
        )
        doc_viewer.setAttribute(Qt.WA_DeleteOnClose)
        doc_viewer.setWindowTitle(
            document_widget.displayName()
        )

        # TODO: Incorporate logic for determining
        # TODO: viewer based on document type
        ph_viewer = PhotoViewer()

        # v_layout = QVBoxLayout()
        # v_layout.addWidget(ph_viewer)
        # doc_viewer.setLayout(v_layout)

        doc_viewer.set_view_widget(ph_viewer)

        doc_viewer.closed.connect(self._on_viewer_closed)

        return doc_viewer

    def remove_viewer(self, viewer_id):
        """
        Close and remove the viewer with the specified viewer ID.
        """
        if viewer_id in self._doc_viewers:
            viewer = self._doc_viewers[viewer_id]
            self._mdi_area.setActiveSubWindow(viewer)
            self._mdi_area.closeActiveSubWindow()

        self._on_viewer_closed(viewer_id)

    def _on_viewer_closed(self,file_id):
        """
        Slot raised when a document viewer is closed.
        """
        if file_id in self._doc_viewers:
            del self._doc_viewers[file_id]