def split_frame(self, frame, orientation):
        """
        Split the given frame either horizontally or vertically.
        :param frame: frame to split
        :param orientation: orientation along which the frame will be split
        """
        opposite_orientation = Qt.Vertical if orientation == Qt.Horizontal else Qt.Horizontal   # get opposite orientation
        parent_splitter = frame.splitter    # get reference to the splitter wherein the frame is embedded (maybe none)
        splitter = None     # variable to hold the splitter that will be used to embed this frame after splitting

        # if the frame is not embedded in a splitter or the orientation of the embedding splitter does not match a new splitter has to be created
        if parent_splitter is None or parent_splitter.orientation() == opposite_orientation:
            splitter = QSplitter(orientation)   # create new splitter

            if parent_splitter is None:     # if the frame was not embedded into a splitter the new splitter is the base splitter
                self.addWidget(splitter)
                self._base_splitter = splitter
                splitter.addWidget(frame)
            else:  # if the frame was embedded into a differently oriented splitter, the new splitter will take its place
                splitter_index = frame.splitter_index   # get the correct position of the new splitter within the parent splitter

                # get the sizes of all the widgets within the parent splitter
                if orientation == Qt.Horizontal:
                    sizes = [parent_splitter.widget(i).geometry().height() for i in range(parent_splitter.count())]
                else:
                    sizes = [parent_splitter.widget(i).geometry().width() for i in range(parent_splitter.count())]

                splitter.addWidget(frame)   # add the frame to the new splitter
                parent_splitter.insertWidget(splitter_index, splitter)  # add the splitter to the parent splitter
                parent_splitter.setSizes(sizes)     # restore the dimensions of the widgets within the parent splitter

            frame.splitter = splitter   # store the reference to the newly created splitter within the frame
        elif parent_splitter.orientation() == orientation:
            splitter = parent_splitter  # if the orientation of the existing splitter matches just use it to proceed

        # store the sizes of all the existing widgets in the splitter
        # half the size of the frame to be split and add an additional size which is also half of the frames current dimension
        geometry = frame.geometry()
        if orientation == Qt.Horizontal:
            sizes = [splitter.widget(i).geometry().height() for i in range(splitter.count())]
            sizes[frame.splitter_index] = geometry.width() / 2
            sizes.insert(frame.splitter_index + 1, geometry.width() / 2)
        else:
            sizes = [splitter.widget(i).geometry().width() for i in range(splitter.count())]
            sizes[frame.splitter_index] = geometry.height() / 2
            sizes.insert(frame.splitter_index + 1, geometry.height() / 2)

        insert_index = frame.splitter_index + 1     # get the index where the new frame should be inserted into the splitter
        new_frame = self._add_modular_frame_()  # create the new frame
        new_frame.splitter = splitter   # set the splitter of the new frame
        splitter.insertWidget(insert_index, new_frame)  # insert the new frame into the splitter
        splitter.setSizes(sizes)    # setup the proper dimensions of all the widgets in the splitter
Esempio n. 2
0
class ChartLayoutManager:
    def __init__(self, parent=None):
        self.parent = parent

        # Create default main chart pane
        self.chart_panes = [
            ChartPane(ChartView(), ChartAxisView()),
        ]

        # Create main time axis pane
        self.time_axis_pane = ChartTimePane(TimeAxisView())

        # Create chart pane container
        self.container = QSplitter(parent)
        self.init_layout(self.container)

    def init_layout(self, container):
        container.setOrientation(Qt.Vertical)
        container.setChildrenCollapsible(False)
        container.setHandleWidth(2)
        container.setContentsMargins(0, 0, 0, 0)

        # init chart panes
        for chart_pane in self.chart_panes:
            container.addWidget(chart_pane.create(self.parent))

    def del_last_pane(self, checked=False):
        count = self.container.count()
        if count > 1:
            self.chart_panes.pop(count - 1)
            self.container.widget(count - 1).deleteLater()

    def del_pane(self, index):
        if index == 0:
            return False

        self.chart_panes.pop(index)
        self.container.widget(index).deleteLater()

    def add_pane(self, pane=None):
        if not pane:
            pane = ChartPane(ChartView(), ChartAxisView())

        self.chart_panes.append(pane)
        self.container.addWidget(pane.create(self.parent))

    def get_chart_panes(self) -> QSplitter:
        return self.container

    def get_time_axis(self) -> QWidget:
        return self.time_axis_pane.create(self.parent)
Esempio n. 3
0
class QuadView(QWidget):
    def __init__(self, parent, view1, view2, view3, view4=None):
        QWidget.__init__(self, parent)

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.installEventFilter(self)

        self.dockableContainer = []

        self.layout = QVBoxLayout()
        self.setLayout(self.layout)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)

        self.splitVertical = QSplitter(Qt.Vertical, self)
        self.layout.addWidget(self.splitVertical)
        self.splitHorizontal1 = QSplitter(Qt.Horizontal, self.splitVertical)
        self.splitHorizontal1.setObjectName("splitter1")
        self.splitHorizontal2 = QSplitter(Qt.Horizontal, self.splitVertical)
        self.splitHorizontal2.setObjectName("splitter2")
        self.splitHorizontal1.splitterMoved.connect(self.horizontalSplitterMoved)
        self.splitHorizontal2.splitterMoved.connect(self.horizontalSplitterMoved)

        self.imageView2D_1 = view1

        self.imageView2D_2 = view2

        self.imageView2D_3 = view3

        self.dock1_ofSplitHorizontal1 = ImageView2DDockWidget(self.imageView2D_1)
        self.dock1_ofSplitHorizontal1.connectHud()
        self.dockableContainer.append(self.dock1_ofSplitHorizontal1)
        self.dock1_ofSplitHorizontal1.onDockButtonClicked.connect(
            lambda arg=self.dock1_ofSplitHorizontal1: self.on_dock(arg)
        )
        self.dock1_ofSplitHorizontal1.onMaxButtonClicked.connect(
            lambda arg=self.dock1_ofSplitHorizontal1: self.on_max(arg)
        )
        self.dock1_ofSplitHorizontal1.onMinButtonClicked.connect(
            lambda arg=self.dock1_ofSplitHorizontal1: self.on_min(arg)
        )
        self.splitHorizontal1.addWidget(self.dock1_ofSplitHorizontal1)

        self.dock2_ofSplitHorizontal1 = ImageView2DDockWidget(self.imageView2D_2)
        self.dock2_ofSplitHorizontal1.onDockButtonClicked.connect(
            lambda arg=self.dock2_ofSplitHorizontal1: self.on_dock(arg)
        )
        self.dock2_ofSplitHorizontal1.onMaxButtonClicked.connect(
            lambda arg=self.dock2_ofSplitHorizontal1: self.on_max(arg)
        )
        self.dock2_ofSplitHorizontal1.onMinButtonClicked.connect(
            lambda arg=self.dock2_ofSplitHorizontal1: self.on_min(arg)
        )
        self.dock2_ofSplitHorizontal1.connectHud()
        self.dockableContainer.append(self.dock2_ofSplitHorizontal1)
        self.splitHorizontal1.addWidget(self.dock2_ofSplitHorizontal1)

        self.dock1_ofSplitHorizontal2 = ImageView2DDockWidget(self.imageView2D_3)
        self.dock1_ofSplitHorizontal2.onDockButtonClicked.connect(
            lambda arg=self.dock1_ofSplitHorizontal2: self.on_dock(arg)
        )
        self.dock1_ofSplitHorizontal2.onMaxButtonClicked.connect(
            lambda arg=self.dock1_ofSplitHorizontal2: self.on_max(arg)
        )
        self.dock1_ofSplitHorizontal2.onMinButtonClicked.connect(
            lambda arg=self.dock1_ofSplitHorizontal2: self.on_min(arg)
        )
        self.dock1_ofSplitHorizontal2.connectHud()
        self.dockableContainer.append(self.dock1_ofSplitHorizontal2)
        self.splitHorizontal2.addWidget(self.dock1_ofSplitHorizontal2)

        self.dock2_ofSplitHorizontal2 = ImageView2DDockWidget(view4)
        self.dockableContainer.append(self.dock2_ofSplitHorizontal2)
        self.splitHorizontal2.addWidget(self.dock2_ofSplitHorizontal2)

        # this is a hack: with 0 ms it does not work...
        QTimer.singleShot(250, self._resizeEqual)

    def _resizeEqual(self):
        if not all([dock.isVisible() for dock in self.dockableContainer]):
            return
        w, h = (
            self.size().width() - self.splitHorizontal1.handleWidth(),
            self.size().height() - self.splitVertical.handleWidth(),
        )

        self.splitVertical.setSizes([h // 2, h // 2])

        if self.splitHorizontal1.count() == 2 and self.splitHorizontal2.count() == 2:
            # docks = [self.imageView2D_1, self.imageView2D_2, self.imageView2D_3, self.testView4]
            docks = []
            for splitter in [self.splitHorizontal1, self.splitHorizontal2]:
                for i in range(splitter.count()):
                    docks.append(splitter.widget(i).graphicsView)

            w1 = [docks[i].minimumSize().width() for i in [0, 2]]
            w2 = [docks[i].minimumSize().width() for i in [1, 3]]
            wLeft = max(w1)
            wRight = max(w2)
            if wLeft > wRight and wLeft > w // 2:
                wRight = w - wLeft
            elif wRight >= wLeft and wRight > w // 2:
                wLeft = w - wRight
            else:
                wLeft = w // 2
                wRight = w // 2
            self.splitHorizontal1.setSizes([wLeft, wRight])
            self.splitHorizontal2.setSizes([wLeft, wRight])

    def eventFilter(self, obj, event):
        if event.type() in [QEvent.WindowActivate, QEvent.Show]:
            self._synchronizeSplitter()
        return False

    def _synchronizeSplitter(self):
        sizes1 = self.splitHorizontal1.sizes()
        sizes2 = self.splitHorizontal2.sizes()
        if len(sizes1) > 0 and sizes1[0] > 0:
            self.splitHorizontal2.setSizes(sizes1)
        elif len(sizes2) > 0 and sizes2[0] > 0:
            self.splitHorizontal1.setSizes(sizes2)

    def resizeEvent(self, event):
        QWidget.resizeEvent(self, event)
        self._synchronizeSplitter()

    def horizontalSplitterMoved(self, x, y):
        if self.splitHorizontal1.count() != 2 or self.splitHorizontal2.count() != 2:
            return
        sizes = self.splitHorizontal1.sizes()
        # What. Nr2
        if self.splitHorizontal2.closestLegalPosition(x, y) < self.splitHorizontal2.closestLegalPosition(x, y):
            sizeLeft = self.splitHorizontal1.closestLegalPosition(x, y)
        else:
            sizeLeft = self.splitHorizontal2.closestLegalPosition(x, y)

        sizeRight = sizes[0] + sizes[1] - sizeLeft
        sizes = [sizeLeft, sizeRight]

        self.splitHorizontal1.setSizes(sizes)
        self.splitHorizontal2.setSizes(sizes)

    def addStatusBar(self, bar):
        self.statusBar = bar
        self.layout.addLayout(self.statusBar)

    def setGrayScaleToQuadStatusBar(self, gray):
        self.quadViewStatusBar.setGrayScale(gray)

    def setMouseCoordsToQuadStatusBar(self, x, y, z):
        self.quadViewStatusBar.setMouseCoords(x, y, z)

    def ensureMaximized(self, axis):
        """
        Maximize the view for the given axis if it isn't already maximized.
        """
        axisDict = {
            0: self.dock2_ofSplitHorizontal1,  # x
            1: self.dock1_ofSplitHorizontal2,  # y
            2: self.dock1_ofSplitHorizontal1,
        }  # z

        if not axisDict[axis]._isMaximized:
            self.switchMinMax(axis)

    def ensureMinimized(self, axis):
        """
        Minimize the view for the given axis if it isn't already minimized.
        """
        axisDict = {
            0: self.dock2_ofSplitHorizontal1,  # x
            1: self.dock1_ofSplitHorizontal2,  # y
            2: self.dock1_ofSplitHorizontal1,
        }  # z

        if axisDict[axis]._isMaximized:
            self.switchMinMax(axis)

    def switchMinMax(self, axis):
        """Switch an AxisViewWidget between from minimized to maximized and vice
        versa.

        Keyword arguments:
        axis -- the axis which is represented by the widget (no default)
                either string or integer
                'x' - 0
                'y' - 1
                'z' - 2
        """

        # TODO: get the mapping information from where it is set! if this is not
        # done properly - do it properly

        if type(axis) == str:
            axisDict = {
                "x": self.dock2_ofSplitHorizontal1,  # x
                "y": self.dock1_ofSplitHorizontal2,  # y
                "z": self.dock1_ofSplitHorizontal1,
            }  # z
        elif type(axis) == int:
            axisDict = {
                0: self.dock2_ofSplitHorizontal1,  # x
                1: self.dock1_ofSplitHorizontal2,  # y
                2: self.dock1_ofSplitHorizontal1,
            }  # z

        dockWidget = axisDict.pop(axis)
        for dWidget in list(axisDict.values()):
            if dWidget._isMaximized:
                dWidget.graphicsView._hud.maximizeButtonClicked.emit()
        dockWidget.graphicsView._hud.maximizeButtonClicked.emit()

    def switchXMinMax(self):
        self.switchMinMax("x")

    def switchYMinMax(self):
        self.switchMinMax("y")

    def switchZMinMax(self):
        self.switchMinMax("z")

    def on_dock(self, dockWidget):
        if dockWidget._isDocked:
            dockWidget.undockView()
            self.on_min(dockWidget)
            dockWidget.minimizeView()
        else:
            dockWidget.dockView()

    def on_max(self, dockWidget):
        dockWidget.setVisible(True)
        for dock in self.dockableContainer:
            if not dockWidget == dock:
                dock.setVisible(False)

        # Force sizes to be updated now
        QApplication.processEvents()

        # On linux, the vertical splitter doesn't seem to refresh unless we do so manually
        # Presumably, this is a QT bug.
        self.splitVertical.refresh()

        # Viewport doesn't update automatically...
        view = dockWidget.graphicsView
        view.viewport().setGeometry(view.rect())

    def on_min(self, dockWidget):

        for dock in self.dockableContainer:
            dock.setVisible(True)

        # Force sizes to be updated now
        QApplication.processEvents()
        self._resizeEqual()

        # Viewports don't update automatically...
        for dock in self.dockableContainer:
            view = dock.graphicsView
            if hasattr(view, "viewport"):
                view.viewport().setGeometry(view.rect())
Esempio n. 4
0
class _s_CentralWidget(QWidget):

###############################################################################
# CentralWidget SIGNALS
###############################################################################

    """
    splitterCentralRotated()
    """
    splitterCentralRotated = pyqtSignal()

###############################################################################

    def __init__(self, parent=None):
        super(_s_CentralWidget, self).__init__(parent)
        self.parent = parent
        #This variables are used to save the splitter sizes before hide
        self._splitterMainSizes = None
        self._splitterAreaSizes = None
        self.lateralPanel = None

        hbox = QHBoxLayout(self)
        hbox.setContentsMargins(0, 0, 0, 0)
        hbox.setSpacing(0)
        #Create Splitters to divide the UI in: MainPanel, Explorer, Misc
        self._splitterArea = QSplitter(Qt.Horizontal)
        self._splitterMain = QSplitter(Qt.Vertical)

        #Create scrollbar for follow mode
        self.scrollBar = QScrollBar(Qt.Vertical, self)
        self.scrollBar.setFixedWidth(20)
        self.scrollBar.setToolTip('Follow Mode: Scroll the Editors together')
        self.scrollBar.hide()
        self.scrollBar.valueChanged[int].connect(self.move_follow_scrolls)

        #Add to Main Layout
        hbox.addWidget(self.scrollBar)
        hbox.addWidget(self._splitterArea)

    def insert_central_container(self, container):
        self.mainContainer = container
        self._splitterMain.insertWidget(0, container)

    def insert_lateral_container(self, container):
        self.lateralPanel = LateralPanel(container)
        self._splitterArea.insertWidget(0, self.lateralPanel)

    def insert_bottom_container(self, container):
        self.misc = container
        self._splitterMain.insertWidget(1, container)

    def showEvent(self, event):
        #Show Event
        QWidget.showEvent(self, event)
        #Avoid recalculate the panel sizes if they are already loaded
        if self._splitterArea.count() == 2:
            return
        #Rearrange widgets on Window
        self._splitterArea.insertWidget(0, self._splitterMain)
        if not event.spontaneous():
            self.change_misc_visibility()
        if bin(settings.UI_LAYOUT)[-1] == '1':
            self.splitter_central_rotate()
        if bin(settings.UI_LAYOUT >> 1)[-1] == '1':
            self.splitter_misc_rotate()
        if bin(settings.UI_LAYOUT >> 2)[-1] == '1':
            self.splitter_central_orientation()
        qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat)
        #Lists of sizes as list of QVariant- heightList = [QVariant, QVariant]
        heightList = list(qsettings.value("window/central/mainSize",
            [(self.height() / 3) * 2, self.height() / 3]))
        widthList = list(qsettings.value("window/central/areaSize",
            [(self.width() / 6) * 5, self.width() / 6]))
        self._splitterMainSizes = [int(heightList[0]), int(heightList[1])]
        self._splitterAreaSizes = [int(widthList[0]), int(widthList[1])]
        #Set the sizes to splitters
        #self._splitterMain.setSizes(self._splitterMainSizes)
        self._splitterMain.setSizes(self._splitterMainSizes)
        self._splitterArea.setSizes(self._splitterAreaSizes)
        self.misc.setVisible(
            qsettings.value("window/show_misc", False, type=bool))

    def change_misc_visibility(self, on_start=False):
        if self.misc.isVisible():
            self._splitterMainSizes = self._splitterMain.sizes()
            self.misc.hide()
            widget = self.mainContainer.get_actual_widget()
            if widget:
                widget.setFocus()
        else:
            self.misc.show()
            self.misc.gain_focus()

    def change_main_visibility(self):
        if self.mainContainer.isVisible():
            self.mainContainer.hide()
        else:
            self.mainContainer.show()

    def change_explorer_visibility(self, force_hide=False):
        if self.lateralPanel.isVisible() or force_hide:
            self._splitterAreaSizes = self._splitterArea.sizes()
            self.lateralPanel.hide()
        else:
            self.lateralPanel.show()

    def splitter_central_rotate(self):
        w1, w2 = self._splitterArea.widget(0), self._splitterArea.widget(1)
        self._splitterArea.insertWidget(0, w2)
        self._splitterArea.insertWidget(1, w1)
        self.splitterCentralRotated.emit()

    def splitter_central_orientation(self):
        if self._splitterArea.orientation() == Qt.Horizontal:
            self._splitterArea.setOrientation(Qt.Vertical)
        else:
            self._splitterArea.setOrientation(Qt.Horizontal)

    def splitter_misc_rotate(self):
        w1, w2 = self._splitterMain.widget(0), self._splitterMain.widget(1)
        self._splitterMain.insertWidget(0, w2)
        self._splitterMain.insertWidget(1, w1)

    def splitter_misc_orientation(self):
        if self._splitterMain.orientation() == Qt.Horizontal:
            self._splitterMain.setOrientation(Qt.Vertical)
        else:
            self._splitterMain.setOrientation(Qt.Horizontal)

    def get_area_sizes(self):
        if self.lateralPanel.isVisible():
            self._splitterAreaSizes = self._splitterArea.sizes()
        return self._splitterAreaSizes

    def get_main_sizes(self):
        if self.misc.isVisible():
            self._splitterMainSizes = self._splitterMain.sizes()
        return self._splitterMainSizes

    def enable_follow_mode_scrollbar(self, val):
        if val:
            editorWidget = self.mainContainer.get_actual_editor()
            maxScroll = editorWidget.verticalScrollBar().maximum()
            position = editorWidget.verticalScrollBar().value()
            self.scrollBar.setMaximum(maxScroll)
            self.scrollBar.setValue(position)
        self.scrollBar.setVisible(val)

    def move_follow_scrolls(self, val):
        widget = self.mainContainer._tabMain.currentWidget()
        diff = widget._sidebarWidget.highest_line - val
        s1 = self.mainContainer._tabMain.currentWidget().verticalScrollBar()
        s2 = self.mainContainer._tabSecondary.\
            currentWidget().verticalScrollBar()
        s1.setValue(val)
        s2.setValue(val + diff)
class QuadView(QWidget):
    def __init__(self, parent, view1, view2, view3, view4=None):
        QWidget.__init__(self, parent)

        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.installEventFilter(self)

        self.dockableContainer = []

        self.layout = QVBoxLayout()
        self.setLayout(self.layout)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)

        self.splitVertical = QSplitter(Qt.Vertical, self)
        self.layout.addWidget(self.splitVertical)
        self.splitHorizontal1 = QSplitter(Qt.Horizontal, self.splitVertical)
        self.splitHorizontal1.setObjectName("splitter1")
        self.splitHorizontal2 = QSplitter(Qt.Horizontal, self.splitVertical)
        self.splitHorizontal2.setObjectName("splitter2")
        self.splitHorizontal1.splitterMoved.connect(
            self.horizontalSplitterMoved)
        self.splitHorizontal2.splitterMoved.connect(
            self.horizontalSplitterMoved)

        self.imageView2D_1 = view1

        self.imageView2D_2 = view2

        self.imageView2D_3 = view3

        self.dock1_ofSplitHorizontal1 = ImageView2DDockWidget(
            self.imageView2D_1)
        self.dock1_ofSplitHorizontal1.connectHud()
        self.dockableContainer.append(self.dock1_ofSplitHorizontal1)
        self.dock1_ofSplitHorizontal1.onDockButtonClicked.connect(
            lambda arg=self.dock1_ofSplitHorizontal1: self.on_dock(arg))
        self.dock1_ofSplitHorizontal1.onMaxButtonClicked.connect(
            lambda arg=self.dock1_ofSplitHorizontal1: self.on_max(arg))
        self.dock1_ofSplitHorizontal1.onMinButtonClicked.connect(
            lambda arg=self.dock1_ofSplitHorizontal1: self.on_min(arg))
        self.splitHorizontal1.addWidget(self.dock1_ofSplitHorizontal1)

        self.dock2_ofSplitHorizontal1 = ImageView2DDockWidget(
            self.imageView2D_2)
        self.dock2_ofSplitHorizontal1.onDockButtonClicked.connect(
            lambda arg=self.dock2_ofSplitHorizontal1: self.on_dock(arg))
        self.dock2_ofSplitHorizontal1.onMaxButtonClicked.connect(
            lambda arg=self.dock2_ofSplitHorizontal1: self.on_max(arg))
        self.dock2_ofSplitHorizontal1.onMinButtonClicked.connect(
            lambda arg=self.dock2_ofSplitHorizontal1: self.on_min(arg))
        self.dock2_ofSplitHorizontal1.connectHud()
        self.dockableContainer.append(self.dock2_ofSplitHorizontal1)
        self.splitHorizontal1.addWidget(self.dock2_ofSplitHorizontal1)

        self.dock1_ofSplitHorizontal2 = ImageView2DDockWidget(
            self.imageView2D_3)
        self.dock1_ofSplitHorizontal2.onDockButtonClicked.connect(
            lambda arg=self.dock1_ofSplitHorizontal2: self.on_dock(arg))
        self.dock1_ofSplitHorizontal2.onMaxButtonClicked.connect(
            lambda arg=self.dock1_ofSplitHorizontal2: self.on_max(arg))
        self.dock1_ofSplitHorizontal2.onMinButtonClicked.connect(
            lambda arg=self.dock1_ofSplitHorizontal2: self.on_min(arg))
        self.dock1_ofSplitHorizontal2.connectHud()
        self.dockableContainer.append(self.dock1_ofSplitHorizontal2)
        self.splitHorizontal2.addWidget(self.dock1_ofSplitHorizontal2)

        self.dock2_ofSplitHorizontal2 = ImageView2DDockWidget(view4)
        self.dockableContainer.append(self.dock2_ofSplitHorizontal2)
        self.splitHorizontal2.addWidget(self.dock2_ofSplitHorizontal2)

        #this is a hack: with 0 ms it does not work...
        QTimer.singleShot(250, self._resizeEqual)

    def _resizeEqual(self):
        if not all([dock.isVisible() for dock in self.dockableContainer]):
            return
        w, h = self.size().width() - self.splitHorizontal1.handleWidth(
        ), self.size().height() - self.splitVertical.handleWidth()

        self.splitVertical.setSizes([h // 2, h // 2])

        if self.splitHorizontal1.count() == 2 and self.splitHorizontal2.count(
        ) == 2:
            #docks = [self.imageView2D_1, self.imageView2D_2, self.imageView2D_3, self.testView4]
            docks = []
            for splitter in [self.splitHorizontal1, self.splitHorizontal2]:
                for i in range(splitter.count()):
                    docks.append(splitter.widget(i).graphicsView)

            w1 = [docks[i].minimumSize().width() for i in [0, 2]]
            w2 = [docks[i].minimumSize().width() for i in [1, 3]]
            wLeft = max(w1)
            wRight = max(w2)
            if wLeft > wRight and wLeft > w // 2:
                wRight = w - wLeft
            elif wRight >= wLeft and wRight > w // 2:
                wLeft = w - wRight
            else:
                wLeft = w // 2
                wRight = w // 2
            self.splitHorizontal1.setSizes([wLeft, wRight])
            self.splitHorizontal2.setSizes([wLeft, wRight])

    def eventFilter(self, obj, event):
        if (event.type() in [QEvent.WindowActivate, QEvent.Show]):
            self._synchronizeSplitter()
        return False

    def _synchronizeSplitter(self):
        sizes1 = self.splitHorizontal1.sizes()
        sizes2 = self.splitHorizontal2.sizes()
        if len(sizes1) > 0 and sizes1[0] > 0:
            self.splitHorizontal2.setSizes(sizes1)
        elif len(sizes2) > 0 and sizes2[0] > 0:
            self.splitHorizontal1.setSizes(sizes2)

    def resizeEvent(self, event):
        QWidget.resizeEvent(self, event)
        self._synchronizeSplitter()

    def horizontalSplitterMoved(self, x, y):
        if self.splitHorizontal1.count() != 2 or self.splitHorizontal2.count(
        ) != 2:
            return
        sizes = self.splitHorizontal1.sizes()
        #What. Nr2
        if self.splitHorizontal2.closestLegalPosition(
                x, y) < self.splitHorizontal2.closestLegalPosition(x, y):
            sizeLeft = self.splitHorizontal1.closestLegalPosition(x, y)
        else:
            sizeLeft = self.splitHorizontal2.closestLegalPosition(x, y)

        sizeRight = sizes[0] + sizes[1] - sizeLeft
        sizes = [sizeLeft, sizeRight]

        self.splitHorizontal1.setSizes(sizes)
        self.splitHorizontal2.setSizes(sizes)

    def addStatusBar(self, bar):
        self.statusBar = bar
        self.layout.addLayout(self.statusBar)

    def setGrayScaleToQuadStatusBar(self, gray):
        self.quadViewStatusBar.setGrayScale(gray)

    def setMouseCoordsToQuadStatusBar(self, x, y, z):
        self.quadViewStatusBar.setMouseCoords(x, y, z)

    def ensureMaximized(self, axis):
        """
        Maximize the view for the given axis if it isn't already maximized.
        """
        axisDict = {
            0: self.dock2_ofSplitHorizontal1,  # x
            1: self.dock1_ofSplitHorizontal2,  # y
            2: self.dock1_ofSplitHorizontal1
        }  # z

        if not axisDict[axis]._isMaximized:
            self.switchMinMax(axis)

    def ensureMinimized(self, axis):
        """
        Minimize the view for the given axis if it isn't already minimized.
        """
        axisDict = {
            0: self.dock2_ofSplitHorizontal1,  # x
            1: self.dock1_ofSplitHorizontal2,  # y
            2: self.dock1_ofSplitHorizontal1
        }  # z

        if axisDict[axis]._isMaximized:
            self.switchMinMax(axis)

    def switchMinMax(self, axis):
        """Switch an AxisViewWidget between from minimized to maximized and vice
        versa.

        Keyword arguments:
        axis -- the axis which is represented by the widget (no default)
                either string or integer 
                'x' - 0
                'y' - 1
                'z' - 2
        """

        #TODO: get the mapping information from where it is set! if this is not
        #done properly - do it properly

        if type(axis) == str:
            axisDict = {
                'x': self.dock2_ofSplitHorizontal1,  # x
                'y': self.dock1_ofSplitHorizontal2,  # y
                'z': self.dock1_ofSplitHorizontal1
            }  # z
        elif type(axis) == int:
            axisDict = {
                0: self.dock2_ofSplitHorizontal1,  # x
                1: self.dock1_ofSplitHorizontal2,  # y
                2: self.dock1_ofSplitHorizontal1
            }  # z

        dockWidget = axisDict.pop(axis)
        for dWidget in list(axisDict.values()):
            if dWidget._isMaximized:
                dWidget.graphicsView._hud.maximizeButtonClicked.emit()
        dockWidget.graphicsView._hud.maximizeButtonClicked.emit()

    def switchXMinMax(self):
        self.switchMinMax('x')

    def switchYMinMax(self):
        self.switchMinMax('y')

    def switchZMinMax(self):
        self.switchMinMax('z')

    def on_dock(self, dockWidget):
        if dockWidget._isDocked:
            dockWidget.undockView()
            self.on_min(dockWidget)
            dockWidget.minimizeView()
        else:
            dockWidget.dockView()

    def on_max(self, dockWidget):
        dockWidget.setVisible(True)
        for dock in self.dockableContainer:
            if not dockWidget == dock:
                dock.setVisible(False)

        # Force sizes to be updated now
        QApplication.processEvents()

        # On linux, the vertical splitter doesn't seem to refresh unless we do so manually
        # Presumably, this is a QT bug.
        self.splitVertical.refresh()

        # Viewport doesn't update automatically...
        view = dockWidget.graphicsView
        view.viewport().setGeometry(view.rect())

    def on_min(self, dockWidget):

        for dock in self.dockableContainer:
            dock.setVisible(True)

        # Force sizes to be updated now
        QApplication.processEvents()
        self._resizeEqual()

        # Viewports don't update automatically...
        for dock in self.dockableContainer:
            view = dock.graphicsView
            if hasattr(view, 'viewport'):
                view.viewport().setGeometry(view.rect())
Esempio n. 6
0
class MainWindow(QMainWindow):
    
    KEY_WINDOW_SIZE = 'main_window/size'
    KEY_WINDOW_MAXIMIZED = 'main_window/maximized'
    KEY_WINDOW_POSITION = 'main_window/position'
    KEY_H_SPLITTER_STATE = 'main_window/h_splitter_state'
    
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle('Mojuru')
        app_icon = QIcon('images/mojuru_logo.png')
        self.setWindowIcon(app_icon)
        
        reload_modules_action = QAction('Reload MainWindow', self)
        reload_modules_action.setShortcut('ctrl+shift+alt+r')
        reload_modules_action.triggered.connect(self.reload_central_widget)
        self.addAction(reload_modules_action)
        
        quit_action = QAction('Quit', self)
        quit_action.setShortcut('ctrl+q')
        quit_action.triggered.connect(self.on_quit)
        self.addAction(quit_action)
        
        self.vertical_splitter = QSplitter(Qt.Vertical, self)
        self.setCentralWidget(self.vertical_splitter)
        self.load_central_widget()
        
        self.file_menu = self.menuBar().addMenu(self.tr('&File'))
        self.file_menu.addAction(quit_action)
        self.file_menu.addSeparator()
        
        self.module_menu = self.menuBar().addMenu(self.tr('&Modules'))
        self.module_menu.addAction(reload_modules_action)
        self.module_menu.addSeparator()
        
        Alter.invoke_all('main_window_init', self)
        
        #restore main window state
        size = ModuleManager.core['settings'].Settings.value(
            self.KEY_WINDOW_SIZE, QSize(600, 400))
        maximized = ModuleManager.core['settings'].Settings.value(
            self.KEY_WINDOW_MAXIMIZED, False)
        position = ModuleManager.core['settings'].Settings.value(
            self.KEY_WINDOW_POSITION, QPoint(0,0))
        if maximized == 'true':
            self.showMaximized()
        else:
            self.resize(size)
            self.move(position)
    
    def closeEvent(self, event):
        self.on_quit()
    
    def save_state(self):
        ModuleManager.core['settings'].Settings.set_value(
            self.KEY_WINDOW_SIZE, self.size())
        ModuleManager.core['settings'].Settings.set_value(
            self.KEY_WINDOW_MAXIMIZED, self.isMaximized())
        ModuleManager.core['settings'].Settings.set_value(
            self.KEY_WINDOW_POSITION, self.pos())
        ModuleManager.core['settings'].Settings.set_value(
            self.KEY_H_SPLITTER_STATE, self.horizontal_splitter.saveState())
    
    def on_quit(self):
        self.save_state()
        self.close()
    
    def load_central_widget(self):
        self.populate_central_widget()
        self.connect_widgets()
    
    def populate_central_widget(self):
        self.vertical_widgets = collections.OrderedDict()
        
        self.horizontal_splitter = QSplitter(
            Qt.Horizontal, self.vertical_splitter)
        self.horizontal_widgets = collections.OrderedDict()
        self.vertical_widgets["horizontal_splitter"] = self.horizontal_splitter
        
        Alter.invoke_all(
            'main_window_add_vertical_widget',
            self.vertical_widgets,
            self
        )
        for widget in self.vertical_widgets.values():
            self.vertical_splitter.addWidget(widget)
        
        Alter.invoke_all(
            'main_window_add_horizontal_widget',
            self.horizontal_widgets,
            self.vertical_splitter
        )
        for widget in self.horizontal_widgets.values():
            self.horizontal_splitter.addWidget(widget)
        
        #restore horizontal splitter state
        state = ModuleManager.core['settings'].Settings.value(
            self.KEY_H_SPLITTER_STATE,
            None
        )
        if state:
            self.horizontal_splitter.restoreState(state)
    
    def connect_widgets(self):
        Alter.invoke_all(
            'main_window_connect_widgets', 
            self.vertical_widgets, 
            self.horizontal_widgets
        )
    
    def reload_central_widget(self):
        self.save_state()
        for index in range(self.vertical_splitter.count()):
            widget = self.vertical_splitter.widget(index)
            widget.hide()
            widget.setParent(None)
            del widget
        Alter.clear()
        ModuleManager.reload_all_modules('core')
        ModuleManager.reload_all_modules('custom')
        self.load_central_widget()
Esempio n. 7
0
class MSplitter(QFrame, MHierarchicalElement):

    VERTICAL = 'vertical'
    HORIZONTAL = 'horizontal'

    def __init__(self, parent_window):
        super().__init__()
        self.setObjectName("main_frame")

        # Construct top-level window elements
        self.main_layout = QVBoxLayout()
        self.setLayout(self.main_layout)
        self.parent_container = None

        #self.set_parent_he(parent_window)

        self.main_splitter = QSplitter()
        self.main_splitter.setObjectName("main_splitter")
        self.main_splitter.show()
        self.main_layout.setContentsMargins(0, 0, 0, 0)

        #self.header_frame = MHeaderBar(self)

        #self.main_layout.addWidget(self.header_frame)
        self.content = self.main_splitter
        self.main_layout.addWidget(self.main_splitter)
        self.show()

        self.setStyleSheet(
            self.styleSheet() +
            "QFrame#main_frame{background-color:rgb(200,200,200)}\r\n"
            "QSplitter::handle#main_splitter"
            "{"
            "    border: 2px solid rgb(50,50,50);"
            "    background-color:rgb(100,100,100)"
            "}"
            "QSplitter::handle:pressed#main_splitter"
            "{"
            "    border: 2px solid rgb(100,100,100);"
            "    background-color:rgb(200,100,20)"
            "}")

        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)

        self.orientation = None

    def set_sizes(self, one, two):
        self.main_splitter.setSizes([one, two])

    def get_sizes(self):
        return self.main_splitter.sizes()

    def add_content(self, container, location=None):

        # if not (type(container) is MContainer):
        #     raise TypeError("Expected type %s, got %s" % (str(MWindow), type(container)))

        if location is None:
            self.main_splitter.addWidget(container)

        elif location is "top":
            self.main_splitter.setOrientation(Qt.Vertical)
            self.main_splitter.insertWidget(0, container)
            self.orientation = self.VERTICAL

        elif location is "left":
            self.main_splitter.setOrientation(Qt.Horizontal)
            self.main_splitter.insertWidget(0, container)
            self.orientation = self.HORIZONTAL

        elif location is "right":
            self.main_splitter.setOrientation(Qt.Horizontal)
            self.main_splitter.insertWidget(1, container)
            self.orientation = self.HORIZONTAL

        elif location is "bottom":
            self.main_splitter.setOrientation(Qt.Vertical)
            self.main_splitter.insertWidget(1, container)
            self.orientation = self.VERTICAL

        container.set_parent_he(self.get_parent_he())
        self.updateGeometry()

    def get_orientation(self):
        return self.orientation

    def get_position(self):
        return self.main_splitter.sizes()

    def get_num_widgets(self):
        return self.main_splitter.count()

    def get_item_at(self, index):
        return self.main_splitter.widget(index)

    #
    # def get_parent_container(self):
    #     return self.parent_container
    #
    # def set_parent_container(self, win):
    #
    #     if type(win) is MWindow or win is None:
    #
    #         # Remove self from old parent
    #         if self.parent_container is not None:
    #             self.parent_container._remove_child_container(self)
    #
    #         # Add self to new parent
    #         if (win is not None):
    #             win._add_child_container(self)
    #
    #         # Set local reference to parent
    #         self.parent_container = win
    #
    #     else:
    #         raise TypeError("Parent window must be type %s, not %s" % (str(type(MWindow)), str(type(win))))

    def show_drop_regions(self):
        pass

    def hide_drop_regions(self):
        pass
class CodecTab(QScrollArea):

    # BUG: codec_frame should have height 210 but has 480.
    # WORKAROUND: manually set height to 210 height.
    # SEE: https://forum.qt.io/topic/42055/qwidget-height-returns-incorrect-value-in-5-3/7
    FRAME_HEIGHT = 210

    def __init__(self, parent, context, commands):
        super(QWidget, self).__init__(parent)
        self._context = context
        self._logger = context.logger()
        self._commands = commands

        self._next_frame_id = 1
        self._frames = QSplitter(Qt.Vertical)
        self._frames.setChildrenCollapsible(False)
        self._frames.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
        self._frames.setContentsMargins(0, 0, 0, 0)

        self._main_frame = QFrame(self)
        self._main_frame_layout = QVBoxLayout()
        self._main_frame_layout.addWidget(self._frames)
        self._main_frame_layout.addWidget(VSpacer(self))
        self._main_frame.setLayout(self._main_frame_layout)
        self.newFrame("", "")

        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.setWidgetResizable(True)
        self.setWidget(self._main_frame)

    def newFrame(self,
                 text,
                 title,
                 previous_frame=None,
                 status=None,
                 msg=None):
        try:
            # BUG: Setting complex default values is not possible in python
            # WORKAROUND: Set default value to None and set real default later.
            if status is None:
                status = StatusWidget.DEFAULT

            if previous_frame and previous_frame.hasNext():
                next_frame = previous_frame.next()
                next_frame.setTitle(title)
                finished = False
                if status == StatusWidget.ERROR:
                    while not finished:
                        next_frame.flashStatus(status, msg)
                        # Display error only for the first frame.
                        msg = None
                        finished = not next_frame.hasNext()
                        next_frame = next_frame.next()
                else:
                    next_frame.setInputText(text, msg is not None
                                            and len(msg) > 0)
                    next_frame.flashStatus(status, msg)

                previous_frame.focusInputText()
            else:
                new_frame = CodecFrame(self, self._context,
                                       self._next_frame_id, self,
                                       self._commands, previous_frame, text)
                self._next_frame_id += 1
                if self._frames.count() > 0:
                    new_frame.flashStatus(status, msg)
                new_frame.setTitle(title)
                new_frame.setContentsMargins(0, 0, 0, 0)
                new_frame.layout().setContentsMargins(0, 0, 0, 0)
                self._frames.addWidget(new_frame)

                # BUG: QSplitter does not allow frames to be wider than the surrounding area (here: QScrollArea).
                # WORKAROUND: Set a fixed size for codec frames and disable handles which prevents users from
                #             trying to resize the codec frames.
                new_frame.setFixedHeight(self.FRAME_HEIGHT)
                self._frames.handle(self._frames.count() - 1).setEnabled(False)

                if previous_frame:
                    previous_frame.focusInputText()
                else:
                    new_frame.focusInputText()
        except Exception as e:
            self._logger.error("Unknown error: {}".format(str(e)))

    def removeFrames(self, frame):
        if frame:
            if frame.previous():
                frame.previous().setNext(None)

            frames_to_remove = [frame]
            while frame.next():
                frames_to_remove.append(frame.next())
                frame = frame.next()
            for frame_to_remove in reversed(frames_to_remove):
                frame_to_remove.deleteLater()

    def getFocussedFrame(self):
        widget = self._frames.focusWidget()
        while widget:
            if isinstance(widget, CodecFrame):
                return widget
            widget = widget.parent()
        return self._frames.widget(0)
class AnalysisWindow(QMainWindow):
    """
    The main window for analysing and processing data.

    Attributes
    ----------
    cs : :class:`~cued_datalogger.api.channel.ChannelSet`
      The ChannelSet containing all the data. Data is accessed through this
      ChannelSet.

    menubar : :class:`PyQt5.QtWidgets.QMenuBar`

    toolbox : :class:`~cued_datalogger.api.toolbox.MasterToolbox`
      The widget containing local tools and operations. Contains four
      toolboxes: :attr:`time_toolbox`, :attr:`frequency_toolbox`,
      :attr:`sonogram_toolbox`, :attr:`circle_fit_toolbox`.

    time_toolbox : :class:`~cued_datalogger.analysis.time_domain.TimeToolbox`
    frequency_toolbox : :class:`~cued_datalogger.analysis.frequency_domain.FrequencyToolbox`
    sonogram_toolbox : :class:`~cued_datalogger.analysis.sonogram.SonogramToolbox`
    circle_fit_toolbox : :class:`~cued_datalogger.analysis.circle_fit.CircleFitToolbox`

    display_tabwidget : :class:`~cued_datalogger.analysis_window.AnalysisDisplayTabWidget`
        The central widget for display.

    freqdomain_widget : :class`~cued_datalogger.analysis.frequency_domain.FrequencyDomainWidget`
    sonogram_widget : :class:`~cued_datalogger.analysis.sonogram.SonogramDisplayWidget`
    circle_widget : :class:`~cued_datalogger.analysis.circle_fit.CircleFitWidget`

    global_master_toolbox : :class:`~cued_datalogger.api.toolbox.MasterToolbox`
      The master toolbox containing the :attr:`global_toolbox`.

    global_toolbox : :class:`~cued_datalogger.api.toolbox.Toolbox`
      The widget containing global tools and operations. Has five tabs,
      containing: <acquisition window launcher>, :attr:`channel_select_widget`,
      :attr:`channel_metadata_widget`, :attr:`addon_widget`,
      :attr:`import_widget`.
    acquisition_window : :class:`~cued_datalogger.acquisition_window.AcquisitionWindow`
    channel_select_widget : :class:`~cued_datalogger.api.channel.ChannelSelectWidget`
    channel_metadata_widget : :class:`~cued_datalogger.api.channel.ChannelMetadataWidget`
    addon_widget : :class:`~cued_datalogger.api.addons.AddonManager`
    import_widget : :class:`~cued_datalogger.api.file_import.DataImportWidget`
    """
    def __init__(self):
        super().__init__()

        self.setWindowTitle('AnalysisWindow')

        self.create_test_channelset()
        self._init_ui()

        self.setFocus()
        self.showMaximized()

    def _init_ui(self):
        # Add the drop-down menu
        self.menubar = self.menuBar()
        self.menubar.addMenu(ProjectMenu(self))

        # # Create the main widget
        self.splitter = QSplitter(self)
        self.splitter.setHandleWidth(5)
        self.splitter.setChildrenCollapsible(False)
        self.setCentralWidget(self.splitter)

        # Create the analysis tools tab widget
        self._init_display_tabwidget()

        # Create the toolbox
        self._init_toolbox()
        self.display_tabwidget.currentChanged.connect(self.toolbox.set_toolbox)
        self.display_tabwidget.setSizePolicy(QSizePolicy.Expanding,
                                             QSizePolicy.Expanding)

        # Create the global toolbox
        self._init_global_master_toolbox()

        # Configure
        self.update_channelset()
        self.goto_time_series()

        # Add the widgets
        self.splitter.addWidget(self.toolbox)
        self.splitter.addWidget(self.display_tabwidget)
        self.splitter.addWidget(self.global_master_toolbox)

    def _init_display_tabwidget(self):
        """Create the display tabwidget."""
        self.display_tabwidget = QTabWidget(self)
        self.timedomain_widget = TimeDomainWidget()
        self.freqdomain_widget = FrequencyDomainWidget()
        self.sonogram_widget = SonogramDisplayWidget()
        self.circle_widget = CircleFitWidget()

        # Create the tabs
        self.display_tabwidget.addTab(self.timedomain_widget, "Time Domain")
        self.display_tabwidget.addTab(self.freqdomain_widget,
                                      "Frequency Domain")
        self.display_tabwidget.addTab(self.sonogram_widget, "Sonogram")
        self.display_tabwidget.addTab(self.circle_widget, "Circle Fit")

        self.display_tabwidget.currentChanged.connect(
            lambda: self.set_selected_channels(self.channel_select_widget.
                                               selected_channels()))

    def _init_toolbox(self):
        """Create the master toolbox"""
        self.toolbox = MasterToolbox(self)
        self.toolbox.sig_collapsed_changed.connect(self._update_splitter)

        # # Time toolbox
        self.time_toolbox = TimeToolbox(self.toolbox)
        self.time_toolbox.sig_convert_to_fft.connect(
            self.goto_frequency_spectrum)
        self.time_toolbox.sig_convert_to_sonogram.connect(self.goto_sonogram)

        # # Frequency toolbox
        self.frequency_toolbox = FrequencyToolbox(self.toolbox)
        self.frequency_toolbox.sig_calculate_transfer_function.connect(
            self.freqdomain_widget.calculate_transfer_function)
        self.frequency_toolbox.sig_convert_to_circle_fit.connect(
            self.goto_circle_fit)
        self.frequency_toolbox.sig_plot_frequency_spectrum.connect(
            lambda: self.freqdomain_widget.update_plot(False))
        self.frequency_toolbox.sig_plot_transfer_function.connect(
            lambda: self.freqdomain_widget.update_plot(True))
        self.frequency_toolbox.sig_plot_type_changed.connect(
            self.freqdomain_widget.set_plot_type)
        self.frequency_toolbox.sig_show_coherence.connect(
            self.freqdomain_widget.set_show_coherence)

        # # Sonogram toolbox
        self.sonogram_toolbox = SonogramToolbox(self.toolbox)
        self.sonogram_toolbox.sig_contour_spacing_changed.connect(
            self.sonogram_widget.update_contour_spacing)
        self.sonogram_toolbox.sig_num_contours_changed.connect(
            self.sonogram_widget.update_num_contours)
        self.sonogram_toolbox.sig_window_overlap_fraction_changed.connect(
            self.sonogram_widget.update_window_overlap_fraction)
        self.sonogram_toolbox.sig_window_width_changed.connect(
            self.sonogram_widget.update_window_width)

        # # Circle Fit toolbox
        self.circle_fit_toolbox = CircleFitToolbox(self.toolbox)
        self.circle_fit_toolbox.sig_show_transfer_fn.connect(
            self.circle_widget.show_transfer_fn)
        self.circle_fit_toolbox.sig_construct_transfer_fn.connect(
            self.circle_widget.construct_transfer_fn)

        self.toolbox.add_toolbox(self.time_toolbox)
        self.toolbox.add_toolbox(self.frequency_toolbox)
        self.toolbox.add_toolbox(self.sonogram_toolbox)
        self.toolbox.add_toolbox(self.circle_fit_toolbox)
        self.toolbox.set_toolbox(0)

    def _init_global_master_toolbox(self):
        self.global_master_toolbox = MasterToolbox()
        self.global_master_toolbox.sig_collapsed_changed.connect(
            self._update_splitter)

        self.global_toolbox = Toolbox('right', self.global_master_toolbox)

        # # Acquisition Window
        self.acquisition_window = None
        self.device_config = DevConfigUI()
        self.device_config.config_button.setText('Open AcquisitionWindow')
        self.device_config.config_button.clicked.connect(
            self.open_acquisition_window)
        self.global_toolbox.addTab(self.device_config, 'Acquisition Window')

        # # Channel Selection
        self.channel_select_widget = ChannelSelectWidget(self.global_toolbox)
        self.channel_select_widget.sig_channel_selection_changed.connect(
            self.set_selected_channels)
        self.global_toolbox.addTab(self.channel_select_widget,
                                   'Channel Selection')

        # # Channel Metadata
        self.channel_metadata_widget = ChannelMetadataWidget(
            self.global_toolbox)
        self.global_toolbox.addTab(self.channel_metadata_widget,
                                   'Channel Metadata')

        self.channel_metadata_widget.metadataChange.connect(
            self.update_channelset)

        # # Addon Manager
        self.addon_widget = AddonManager(self)
        self.global_toolbox.addTab(self.addon_widget, 'Addon Manager')

        # # Import
        self.import_widget = DataImportWidget(self)
        self.import_widget.sig_extend_channelset.connect(
            self.extend_channelset)
        self.import_widget.sig_replace_channelset.connect(
            self.replace_channelset)
        self.global_toolbox.addTab(self.import_widget, 'Import Files')

        # # Export
        self.export_widget = DataExportWidget(self)
        self.global_toolbox.addTab(self.export_widget, 'Export Files')

        self.global_master_toolbox.add_toolbox(self.global_toolbox)

    def _update_splitter(self):
        # Get the current sizes of everything
        sizes = self.splitter.sizes()
        # Adjust the size of the sender to be equal to its size hint
        for i in range(self.splitter.count()):
            if self.sender() == self.splitter.widget(i):
                sizes[i] = self.sender().sizeHint().width()
        # Set the sizes
        self.splitter.setSizes(sizes)
        self.splitter.setStretchFactor(0, 0)
        self.splitter.setStretchFactor(1, 1)
        self.splitter.setStretchFactor(2, 0)

    #---------------------- Acquisition window methods ------------------------
    def open_acquisition_window(self):
        if not self.acquisition_window:
            recType, configs = self.device_config.read_device_config()
            if not any([c is None for c in configs]):
                self.acquisition_window = AcquisitionWindow(
                    self, recType, configs)
            else:
                self.acquisition_window = AcquisitionWindow(self)
            self.acquisition_window.sig_closed.connect(
                self.close_acquisition_window)
            self.acquisition_window.sig_transfer_function_data_saved.connect(
                self.receive_data)
            self.acquisition_window.sig_time_series_data_saved.connect(
                self.receive_data)
            self.acquisition_window.show()

    def receive_data(self, received_cs):
        self.replace_channelset(received_cs)

        if self.cs.channels[0].is_dataset("transfer_function"):
            self.goto_transfer_function()
        else:
            self.goto_time_series()

    def auto_change_tab(self):
        current_widget = self.display_tabwidget.currentWidget()

        if (current_widget is self.circle_widget
                and self.cs.channels[0].is_dataset("transfer_function")):
            # Remain here
            pass
        elif (current_widget is self.sonogram_widget
              and self.cs.channels[0].is_dataset("sonogram")):
            # Remain here
            pass
        elif (current_widget is self.freqdomain_widget
              and self.cs.channels[0].is_dataset("spectrum")):
            # Remain here
            # Switch the plot type
            self.frequency_toolbox.set_plot_spectrum()
        elif (current_widget is self.freqdomain_widget
              and self.cs.channels[0].is_dataset("transfer_function")):
            # Remain here
            # Switch the plot type
            self.frequency_toolbox.set_plot_transfer_function()
        else:
            if self.cs.channels[0].is_dataset("transfer_function"):
                self.display_tabwidget.setCurrentWidget(self.freqdomain_widget)
                self.frequency_toolbox.set_plot_transfer_function()
            elif self.cs.channels[0].is_dataset("spectrum"):
                self.display_tabwidget.setCurrentWidget(self.freqdomain_widget)
                self.frequency_toolbox.set_plot_spectrum()
            elif self.cs.channels[0].is_dataset("sonogram"):
                self.display_tabwidget.setCurrentWidget(self.sonogram_widget)
            else:
                self.display_tabwidget.setCurrentWidget(self.timedomain_widget)

    def close_acquisition_window(self):
        self.acquisition_window.sig_closed.disconnect()
        self.acquisition_window = None

    #---------------------------- Tab methods ---------------------------------
    def goto_time_series(self, switch_to_tab=True):
        if switch_to_tab:
            self.display_tabwidget.setCurrentWidget(self.timedomain_widget)
        self.timedomain_widget.set_selected_channels(
            self.channel_select_widget.selected_channels())

    def goto_frequency_spectrum(self, switch_to_tab=True):
        if switch_to_tab:
            # Switch to frequency domain tab
            self.display_tabwidget.setCurrentWidget(self.freqdomain_widget)
        self.freqdomain_widget.set_selected_channels(
            self.channel_select_widget.selected_channels())
        self.freqdomain_widget.calculate_spectrum()
        self.frequency_toolbox.set_plot_spectrum()

    def goto_transfer_function(self, switch_to_tab=True):
        if switch_to_tab:
            self.display_tabwidget.setCurrentWidget(self.freqdomain_widget)
        self.freqdomain_widget.set_selected_channels(
            self.channel_select_widget.selected_channels())
        # TODO: calculate TF function if none is found
        self.freqdomain_widget.calculate_transfer_function()
        self.frequency_toolbox.set_plot_transfer_function()

    def goto_sonogram(self, switch_to_tab=True):
        if switch_to_tab:
            self.display_tabwidget.setCurrentWidget(self.sonogram_widget)
        self.sonogram_widget.set_selected_channels(
            self.channel_select_widget.selected_channels())
        self.sonogram_widget.calculate_sonogram()

    def goto_circle_fit(self, switch_to_tab=True):
        if switch_to_tab:
            self.display_tabwidget.setCurrentWidget(self.circle_widget)
        self.circle_widget.set_selected_channels(
            self.channel_select_widget.selected_channels())

    #------------------ ChannelSet methods ------------------------------------
    def create_test_channelset(self):
        self.cs = ChannelSet(5)
        t = np.arange(0, 0.5, 1 / 5000)
        for i, channel in enumerate(self.cs.channels):
            self.cs.set_channel_metadata(i, {'sample_rate': 5000})
            self.cs.add_channel_dataset(i, 'time_series',
                                        np.sin(t * 2 * np.pi * 100 * (i + 1)))
            channel.name = "Channel {}".format(i)
        self.cs.add_channel_dataset(
            i, 'time_series',
            np.sin(t * 2 * np.pi * 100 * (i + 1)) * np.exp(-t / t[-1]))

    def extend_channelset(self, cs):
        if isinstance(cs, ChannelSet):
            self.cs.channels.extend(cs.channels)
            self.update_channelset()
            self.auto_change_tab()
        else:
            print("Failed to extend ChannelSet: {} not a ChannelSet".format(
                type(cs)))

    def replace_channelset(self, cs):
        if isinstance(cs, ChannelSet):
            self.cs = cs
            self.update_channelset()
            self.auto_change_tab()
        else:
            print("Failed to replace ChannelSet: {} not a ChannelSet".format(
                type(cs)))

    def set_selected_channels(self, channels):
        self.display_tabwidget.currentWidget().set_selected_channels(channels)
        if self.display_tabwidget.currentWidget() is self.sonogram_widget:
            self.sonogram_toolbox.set_selected_channels(channels)

    def update_channelset(self):
        self.channel_select_widget.set_channel_set(self.cs)
        self.channel_metadata_widget.set_channel_set(self.cs)
        self.export_widget.set_channel_set(self.cs)
Esempio n. 10
0
class MainWindow(QMainWindow):
    def __init__(self, *args):
        QMainWindow.__init__(self, *args)
        self.setWindowIcon(QIcon(str(images_path.joinpath('qtifm512.png'))))

        # load config
        self.config = Config()
        self.config.load()

        self.move(self.config.mainwindow_x, self.config.mainwindow_y)
        self.resize(self.config.mainwindow_witdh,
                    self.config.mainwindow_height)

        # Actions
        self.exit_action = QAction(_('Exit'), self)
        self.exit_action.setMenuRole(QAction.QuitRole)
        self.exit_action.setShortcut('Ctrl+Q')
        self.about_action = QAction(_('About'), self)
        self.about_action.setMenuRole(QAction.AboutRole)

        self.new_action = QAction(QIcon.fromTheme('document-new'), _('New'))
        self.new_action.setShortcut('Ctrl+N')
        self.open_action = QAction(QIcon.fromTheme('document-open'),
                                   _('Open...'))
        self.open_action.setShortcut('Ctrl+O')
        self.save_action = QAction(QIcon.fromTheme('document-save'), _('Save'))
        self.save_action.setShortcut('Ctrl+S')
        self.saveas_action = QAction(QIcon.fromTheme('document-save-as'),
                                     _('Save As...'))
        self.saveas_action.setShortcut('Shift+Ctrl+S')
        self.clear_recent_files_action = QAction(_('Clear Items'))
        self.settings_action = QAction(_('Settings'))

        self.find_next_action = QAction(QIcon.fromTheme('down'),
                                        _('Find Next'))
        self.find_next_action.setShortcut('F3')
        self.find_previous_action = QAction(QIcon.fromTheme('up'),
                                            _('Find Previous'))
        self.find_previous_action.setShortcut('Ctrl+F3')

        self.normal_size_action = QAction(QIcon.fromTheme('zoom-original'),
                                          _('Normal Size'))
        self.normal_size_action.setShortcut('Ctrl+0')
        self.zoom_in_action = QAction(QIcon.fromTheme('zoom-in'), _('Zoom In'))
        self.zoom_in_action.setShortcut('Ctrl++')
        self.zoom_out_action = QAction(QIcon.fromTheme('zoom-out'),
                                       _('Zoom Out'))
        self.zoom_out_action.setShortcut('Ctrl+-')

        # Menu Bar
        file_menu = self.menuBar().addMenu(_('File'))
        file_menu.addAction(self.new_action)
        file_menu.addAction(self.open_action)
        self.recent_files_menu = file_menu.addMenu(_('Open recent'))
        file_menu.addAction(self.save_action)
        file_menu.addAction(self.saveas_action)
        file_menu.addSeparator()
        file_menu.addAction(self.settings_action)
        file_menu.addSeparator()
        file_menu.addAction(self.exit_action)

        help_menu = self.menuBar().addMenu(_('Help'))
        help_menu.addAction(self.about_action)

        # Widgets
        self.splitter = QSplitter(Qt.Horizontal)
        self.splitter.setHandleWidth(5)
        self.editor = Editor(self, self.config.editor_dark_theme)
        self.map_view = MapView(self, self.config)
        self.find_edit = QLineEdit()
        self.find_edit.setFixedWidth(200)

        # Tool bar
        tool_bar = self.addToolBar('Edit')
        tool_bar.setFloatable(False)
        tool_bar.setMovable(False)
        tool_bar.addAction(self.new_action)
        tool_bar.addAction(self.open_action)
        tool_bar.addAction(self.save_action)
        tool_bar.addAction(self.saveas_action)
        tool_bar.addSeparator()
        tool_bar.addWidget(QLabel(_('Find:') + ' '))
        tool_bar.addWidget(self.find_edit)
        tool_bar.addAction(self.find_next_action)
        tool_bar.addAction(self.find_previous_action)
        tool_bar.addSeparator()
        tool_bar.addAction(self.normal_size_action)
        tool_bar.addAction(self.zoom_in_action)
        tool_bar.addAction(self.zoom_out_action)

        # Connects
        self.new_action.triggered.connect(self.editor.new_file)
        self.open_action.triggered.connect(self.editor.open_file)
        self.save_action.triggered.connect(self.editor.save_file)
        self.saveas_action.triggered.connect(self.editor.save_file_as)
        self.about_action.triggered.connect(self.show_about_dialog)
        self.clear_recent_files_action.triggered.connect(
            self.editor.clear_recent_files)
        self.settings_action.triggered.connect(self.show_settings)
        self.exit_action.triggered.connect(self.close)
        self.normal_size_action.triggered.connect(self.map_view.normal_size)
        self.zoom_in_action.triggered.connect(self.map_view.zoom_in)
        self.zoom_out_action.triggered.connect(self.map_view.zoom_out)
        self.find_next_action.triggered.connect(self.find_next)
        self.find_previous_action.triggered.connect(self.find_previous)

        self.editor.map_changed_signal.connect(self.map_view.create_maps)
        self.editor.map_cleared_signal.connect(self.map_view.clear_maps)

        self.map_view.map_view_changed_signal.connect(self.enable_map_actions)

        self.find_edit.textChanged.connect(self.find_edit_text_changed)
        self.find_edit.returnPressed.connect(self.find_next)

        # Layout
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        central_layout = QVBoxLayout()
        central_layout.setContentsMargins(0, 0, 0,
                                          0)  # left, top, right, bottom
        central_widget.setLayout(central_layout)
        central_layout.addWidget(self.splitter)
        self.statusBar().setSizeGripEnabled(False)
        self.statusBar().addWidget(self.editor.cursor_position_label, 1)
        self.statusBar().addWidget(self.editor.editor_modified_label)
        self.statusBar().addWidget(self.map_view.zoom_factor_label)

        self.splitter.addWidget(self.editor)
        self.splitter.addWidget(self.map_view)

        if len(self.config.mainwindow_splitter_sizes) > 0:
            self.splitter.setSizes(self.config.mainwindow_splitter_sizes)

        if self.config.editor_last_file is not None:
            self.editor.open_path(self.config.editor_last_file,
                                  check_modified=False)

        self.find_next_action.setEnabled(False)
        self.find_previous_action.setEnabled(False)

    @pyqtSlot()
    def enable_map_actions(self):
        self.zoom_in_action.setEnabled(self.map_view.zoom_in_allowed())
        self.zoom_out_action.setEnabled(self.map_view.zoom_out_allowed())
        self.normal_size_action.setEnabled(self.map_view.valid)
        self.map_view.update_zoom_factor_status()

    @pyqtSlot()
    def show_about_dialog(self):
        dialog = AboutDialog(self)
        dialog.exec_()

    @pyqtSlot()
    def show_settings(self):
        dialog = SettingsDialog(self)
        dialog.ifm_command_edit.setText(self.config.map_ifm_command)
        dialog.fig2dev_command_edit.setText(self.config.map_fig2dev_command)
        dialog.magnifcation_factor_edit.setValue(
            self.config.map_fig2dev_magnification_factor)
        dialog.dark_theme_check.setChecked(self.config.editor_dark_theme)
        dialog.helvetica_check.setChecked(
            self.config.map_ifm_helvetica_as_default)
        dialog.image_per_map_check.setChecked(
            self.config.map_ifm_create_image_per_map)
        dark_theme = self.config.editor_dark_theme

        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.config.map_ifm_command = dialog.ifm_command_edit.text().strip(
            )
            self.config.map_fig2dev_command = dialog.fig2dev_command_edit.text(
            ).strip()
            self.config.map_fig2dev_magnification_factor = dialog.magnifcation_factor_edit.value(
            )
            self.config.editor_dark_theme = dialog.dark_theme_check.isChecked()
            self.config.map_ifm_helvetica_as_default = dialog.helvetica_check.isChecked(
            )
            self.config.map_ifm_create_image_per_map = dialog.image_per_map_check.isChecked(
            )

            if self.config.editor_dark_theme != dark_theme:
                self.editor.reset_highlighter(self.config.editor_dark_theme)

    @pyqtSlot()
    def find_edit_text_changed(self):
        flag = len(self.find_edit.text()) > 0
        self.find_next_action.setEnabled(flag)
        self.find_previous_action.setEnabled(flag)

    @pyqtSlot()
    def find_next(self):
        text = self.find_edit.text()
        if len(text) > 0:
            self.editor.find(text)

    @pyqtSlot()
    def find_previous(self):
        text = self.find_edit.text()
        if len(text) > 0:
            self.editor.find(text, QTextDocument.FindBackward)

    def closeEvent(self, event):
        if self.editor.abort_if_modified(_('Exit')):
            event.ignore()
        else:
            event.accept()

        self.config.mainwindow_witdh = self.width()
        self.config.mainwindow_height = self.height()
        self.config.mainwindow_x = self.x()
        self.config.mainwindow_y = self.y()

        self.config.mainwindow_splitter_sizes = []
        for i in range(0, self.splitter.count()):
            self.config.mainwindow_splitter_sizes.append(
                self.splitter.sizes()[i])

        self.config.editor_last_file = self.editor.current_file

        self.config.save()
Esempio n. 11
0
class PanelContainer(QWidget):
    def __init__(self, panelWin):
        super(QWidget, self).__init__()

        self.panelWindow = panelWin
        self.panelCount = 0

        self.mainLayout = QGridLayout(self)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)

        self.splitter = QSplitter(self)
        self.containerParent = 0

        self.mainLayout.addWidget(self.splitter, 0, 0)

    def splitter(self):
        return self.splitter

    def addPanel(self, panel=None):
        if panel:
            panel.setParent(self)
            panel.setContainer(self)
            self.splitter.addWidget(panel)
            self.panelCount += 1
            self.updatePanelSignals(panel)
        else:
            panel = self.createPanel()
            self.splitter.addWidget(panel)
            return panel

    def addPanelSplit(self, panel, direction):
        panel = PanelWidget(self) if 0 else panel

        # Store original size
        origSize = panel.size()

        # reparent the panel
        panel.setParent(self)
        panel.setContainer(self)

        # set orientation and add the panel
        self.splitter.setOrientation(direction)
        self.splitter.addWidget(panel)

        # add another panel for split
        panel = self.createPanel()
        self.splitter.addWidget(panel)

        sizes = list()
        origSize *= 0.5
        if direction == Qt.Horizontal:
            sizes.append(origSize.width())
            sizes.append(origSize.width())
        else:
            sizes.append(origSize.height())
            sizes.append(origSize.height())

        self.splitter.setSizes(sizes)
        self.panelCount += 1

    def addContainer(self, child):
        child = PanelContainer(self) if 0 else child
        self.splitter.addWidget(child)
        child.setParentContainer(self)

    def insertContainer(self, child, index):
        child = PanelContainer(self) if 0 else child
        self.splitter.insertWidget(index, child)
        child.setParentContainer(self)

    def setParentContainer(self, parent):
        self.containerParent = parent

    def parentContainer(self):
        return self.containerParent

    def childContainers(self):
        # childContainers = list()
        # for index in range(0, self.splitter.count()):
        #     container = self.splitter.widget(index)
        #     if container:
        #         childContainers.append(container)
        return self.sortedChildren()

    def panels(self):
        # panels = list()
        # for index in range(0, self.splitter.count()):
        #     panel = self.splitter.widget(index)
        #     if panel:
        #         panels.append(panel)
        return self.sortedChildren()

    def sortedChildren(self):
        return (self.splitter.widget(index) for index in range(self.splitter.count()))

    def numberOfPanels(self):
        return self.panelCount

    def createPanel(self):
        panel = PanelWidget(self)
        panel.createMenu(WorkbenchWidget.panelNames())
        self.connectPanelSignals(panel)
        self.panelCount += 1
        return panel

    def connectPanelSignals(self, panel):
        panel = PanelWidget(self) if 0 else panel
        panel.panelSplit.connect(lambda: self.panelWindow.splitPanel())
        panel.panelFloat.connect(lambda : self.panelWindow.floatPanel())
        panel.panelClosed.connect(lambda : self.panelWindow.closePanel())
        panel.panelMenuTriggered.connect(lambda : self.panelWindow.closePanel())
        panel.tabClosed.connect(lambda : self.panelWindow.closePanel())

    def updatePanelSignals(self, panel):
        panel = PanelWidget(self) if 0 else panel
        panel.panelSplit.disconnect()
        panel.panelFloat.disconnect()
        panel.panelClosed.disconnect()
        panel.panelMenuTriggered.disconnect()
        panel.tabClosed.disconnect()
Esempio n. 12
0
class MainWindow(QMainWindow):
    
    KEY_WINDOW_SIZE = 'main_window/size'
    KEY_WINDOW_MAXIMIZED = 'main_window/maximized'
    KEY_WINDOW_POSITION = 'main_window/position'
    KEY_H_SPLITTER_STATE = 'main_window/h_splitter_state'
    
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle('Mojuru')
        app_icon = QIcon('images/mojuru_logo.png')
        self.setWindowIcon(app_icon)
        
        reload_modules_action = QAction('Reload MainWindow', self)
        reload_modules_action.setShortcut('ctrl+shift+alt+r')
        reload_modules_action.triggered.connect(self.reload_central_widget)
        self.addAction(reload_modules_action)
        
        quit_action = QAction('Quit', self)
        quit_action.setShortcut('ctrl+q')
        quit_action.triggered.connect(self.on_quit)
        self.addAction(quit_action)
        
        self.vertical_splitter = QSplitter(Qt.Vertical, self)
        self.setCentralWidget(self.vertical_splitter)
        self.load_central_widget()
        
        self.file_menu = self.menuBar().addMenu(self.tr('&File'))
        self.file_menu.addAction(quit_action)
        self.file_menu.addSeparator()
        
        self.module_menu = self.menuBar().addMenu(self.tr('&Modules'))
        self.module_menu.addAction(reload_modules_action)
        self.module_menu.addSeparator()
        
        Alter.invoke_all('main_window_init', self)
        
        #restore main window state
        size = ModuleManager.core['settings'].Settings.value(
            self.KEY_WINDOW_SIZE, QSize(600, 400))
        maximized = ModuleManager.core['settings'].Settings.value(
            self.KEY_WINDOW_MAXIMIZED, False)
        position = ModuleManager.core['settings'].Settings.value(
            self.KEY_WINDOW_POSITION, QPoint(0,0))
        if maximized == 'true':
            self.showMaximized()
        else:
            self.resize(size)
            self.move(position)
    
    def closeEvent(self, event):
        self.on_quit()
    
    def save_state(self):
        ModuleManager.core['settings'].Settings.set_value(
            self.KEY_WINDOW_SIZE, self.size())
        ModuleManager.core['settings'].Settings.set_value(
            self.KEY_WINDOW_MAXIMIZED, self.isMaximized())
        ModuleManager.core['settings'].Settings.set_value(
            self.KEY_WINDOW_POSITION, self.pos())
        ModuleManager.core['settings'].Settings.set_value(
            self.KEY_H_SPLITTER_STATE, self.horizontal_splitter.saveState())
    
    def on_quit(self):
        self.save_state()
        self.close()
    
    def load_central_widget(self):
        self.populate_central_widget()
        self.connect_widgets()
    
    def populate_central_widget(self):
        self.vertical_widgets = collections.OrderedDict()
        
        self.horizontal_splitter = QSplitter(
            Qt.Horizontal, self.vertical_splitter)
        self.horizontal_widgets = collections.OrderedDict()
        self.vertical_widgets["horizontal_splitter"] = self.horizontal_splitter
        
        Alter.invoke_all(
            'main_window_add_vertical_widget',
            self.vertical_widgets,
            self
        )
        for widget in self.vertical_widgets.values():
            self.vertical_splitter.addWidget(widget)
        
        Alter.invoke_all(
            'main_window_add_horizontal_widget',
            self.horizontal_widgets,
            self.vertical_splitter
        )
        for widget in self.horizontal_widgets.values():
            self.horizontal_splitter.addWidget(widget)
        
        #restore horizontal splitter state
        state = ModuleManager.core['settings'].Settings.value(
            self.KEY_H_SPLITTER_STATE,
            None
        )
        if state:
            self.horizontal_splitter.restoreState(state)
    
    def connect_widgets(self):
        Alter.invoke_all(
            'main_window_connect_widgets', 
            self.vertical_widgets, 
            self.horizontal_widgets
        )
    
    def reload_central_widget(self):
        self.save_state()
        for index in range(self.vertical_splitter.count()):
            widget = self.vertical_splitter.widget(index)
            widget.hide()
            widget.setParent(None)
            del widget
        Alter.clear()
        ModuleManager.reload_all_modules('core')
        ModuleManager.reload_all_modules('custom')
        self.load_central_widget()
    
    def add_action(self, name, callback, **kwargs):
        """
        Ajoute une action au context menu et au widget lui même.
        Créer une fonction à la volé pour fournir des arguments aux fonctions
        de rappel.
        """
        action = QAction(name, self)
        if 'icon' in kwargs:
            action.setIcon(kwargs['icon'])
        if 'shortcut' in kwargs:
            action.setShortcut(kwargs['shortcut'])
        action.setShortcutContext(Qt.WidgetWithChildrenShortcut)
        action.triggered.connect(self.__wrapper(callback, **kwargs))
        self.addAction(action)
        if 'menu' in kwargs:
            kwargs['menu'].addAction(action)

    def add_separator(self, menu):
        """Simple abstraction of self.context_menu.addSeparator()"""
        menu.addSeparator()
    
    def __wrapper(self, callback, **kwargs):
        def __new_function():
            """
            __new_function représente la forme de tous les callbacks connecté
            à une action pour pouvoir utiliser les raccourcis en même temps que
            le menu contextuel.
            """
            args = [
                kwargs['instance'] if 'instance' in kwargs else self
            ]
            callback(*args)
        return __new_function
Esempio n. 13
0
class WebTab(QWidget):

    class SavedTab(object):
        def __init__(self, webTab=None):
            self.title = ''
            self.url = QUrl()
            self.icon = QIcon()
            self.history = QByteArray()
            self.isPinned = False
            self.zoomLevel = 1
            self.parentTab = -1
            self.childTabs = []
            self.sessionData = {}
            if webTab:
                self.setWebTab(webTab)

        def __getstate__(self):
            result = dict(self.__dict__)
            result['url'] = result['url'].toEncoded()
            data = QByteArray()
            ds = QDataStream(data, QIODevice.WriteOnly)
            ds.writeQVariant(self.icon)
            result['icon'] = data.data()
            return result

        def __setstate__(self, state):
            for key, val in state.items():
                if key == 'url':
                    self.__dict__[key] = QUrl.fromEncoded(val)
                elif key == 'icon':
                    ds = QDataStream(QByteArray(val))
                    self.__dict__[key] = ds.readQVariant()
                else:
                    self.__dict__[key] = val

        def setWebTab(self, webTab):
            self.title = webTab.title()
            self.url = webTab.url()
            self.icon = webTab.icon()
            self.history = webTab.historyData()
            self.isPinned = webTab.isPinned()
            self.zoomLevel = webTab.zoomLevel()
            if webTab.parentTab():
                self.parentTab = webTab.parentTab().tabIndex()
            else:
                self.parentTab = -1
            self.childTabs = [ tab.tabIndex() for tab in webTab.childTabs() ]
            self.sessionData = webTab.sessionData()

        def isValid(self):
            return not self.url.isEmpty() or not self.history.isEmpty()

        def clear(self):
            self.title = ''
            self.url = QUrl()
            self.icon = QIcon()
            self.history = QByteArray()
            self.isPinned = False
            self.zoomLevel = 1
            self.parentTab = -1
            self.childTabs = []
            self.sessionData = {}

    # type AddChildBehavior
    AppendChild = 0
    PrependChild = 1

    s_addChildBehavior = AppendChild

    def __init__(self, parent=None):
        super(WebTab, self).__init__(parent)
        self.setObjectName('webtab')

        self._tabBar = None
        self._window = None
        self._parentTab = None
        self._childTabs = []
        self._sessionData = {}
        self._savedTab = self.SavedTab()
        self._isPinned = False
        self._isCurrentTab = False

        self._webView = TabbedWebView(self)
        self._webView.setPage(WebPage())
        self._webView.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
        self.setFocusProxy(self._webView)

        self._locationBar = LocationBar(self)
        self._locationBar.setWebView(self._webView)

        self._tabIcon = TabIcon(self)
        self._tabIcon.setWebTab(self)

        self._layout = QVBoxLayout(self)
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(0)
        self._layout.addWidget(self._webView)

        viewWidget = QWidget(self)
        viewWidget.setLayout(self._layout)

        self._splitter = QSplitter(Qt.Vertical, self)
        self._splitter.setChildrenCollapsible(False)
        self._splitter.addWidget(viewWidget)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        layout.addWidget(self._splitter)
        self.setLayout(layout)

        self._notificationWidget = QWidget(self)
        self._notificationWidget.setAutoFillBackground(True)
        pal = self._notificationWidget.palette()
        pal.setColor(QPalette.Window, pal.window().color().darker(110))
        self._notificationWidget.setPalette(pal)

        nlayout = QVBoxLayout(self._notificationWidget)
        nlayout.setSizeConstraint(QLayout.SetMinAndMaxSize)
        nlayout.setContentsMargins(0, 0, 0, 0)
        nlayout.setSpacing(1)

        self._webView.showNotification.connect(self.showNotification)
        self._webView.loadFinished.connect(self.loadFinished)
        self._webView.titleChanged.connect(self.titleWasChanged)
        self._webView.titleChanged.connect(self.titleChanged)
        self._webView.iconChanged.connect(self.iconChanged)

        self._webView.backgroundActivityChanged.connect(self.backgroundActivityChanged)
        self._webView.loadStarted.connect(lambda: self.loadingChanged.emit(True))
        self._webView.loadFinished.connect(lambda: self.loadingChanged.emit(False))

        def pageChanged(page):
            page.audioMutedChanged.connect(self.playingChanged)
            page.recentlyAudibleChanged.connect(self.mutedChanged)

        pageChanged(self._webView.page())
        self._webView.pageChanged.connect(pageChanged)

        def tabIconResized():
            if self._tabBar:
                self._tabBar.update()
        self._tabIcon.resized.connect(tabIconResized)

    def browserWindow(self):
        '''
        @return BrowserWindow
        '''
        return self._window

    def webView(self):
        '''
        @return TabbedWebView
        '''
        return self._webView

    def locationBar(self):
        '''
        @return LocationBar
        '''
        return self._locationBar

    def tabIcon(self):
        '''
        @return TabIcon
        '''
        return self._tabIcon

    def parentTab(self):
        '''
        @return WebTab
        '''
        return self._parentTab

    def setParentTab(self, tab):
        if self._isPinned or self._parentTab == tab:
            return
        if tab and tab.isPinned():
            return

        if self._parentTab:
            index = self._parentTab._childTabs.index(self)
            if index >= 0:
                self._parentTab._childTabs.pop(index)
                self._parentTab.childTabRemoved.emit(self, index)
        self._parentTab = tab

        if tab:
            self._parentTab = None
            tab.addChildTab(self)
        else:
            self.parentTabChanged.emit(self._parentTab)

    def addChildTab(self, tab, index=-1):
        if self._isPinned or not tab or tab.isPinned():
            return

        oldParent = tab._parentTab
        tab._parentTab = self
        if oldParent:
            index = oldParent._childTabs.index(tab)
            if index >= 0:
                oldParent._childTabs.pop(index)
                oldParent.childTabRemoved.emit(tab, index)

        if index < 0 or index > len(self._childTabs):
            index = 0
            if self.addChildBehavior() == self.AppendChild:
                index = len(self._childTabs)
            else:  # PrependChild
                index = 0

        self._childTabs.insert(index, tab)
        self.childTabAdded.emit(tab, index)
        tab.parentTabChanged.emit(self)

    def childTabs(self):
        '''
        @return QVector<WebTab*>
        '''
        return self._childTabs

    def sessionData(self):
        '''
        @return {}
        '''
        return self._sessionData

    def setSessionData(self, key, value):
        self._sessionData[key] = value

    def url(self):
        if self.isRestored():
            if self._webView.url().isEmpty() and self._webView.isLoading():
                return self._webView.page().requestedUrl()
            return self._webView.url()
        else:
            return self._savedTab.url

    def title(self, allowEmpty=False):
        if self.isRestored():
            return self._webView.title(allowEmpty)
        else:
            return self._savedTab.title

    def icon(self, allowNull=False):
        if self.isRestored():
            return self._webView.icon(allowNull)
        if allowNull or not self._savedTab.icon.isNull():
            return self._savedTab.icon
        return IconProvider.emptyWebIcon()

    def history(self):
        '''
        @return QWebEngineHistory
        '''
        return self._webView.history()

    def zoomLevel(self):
        return self._webView.zoomLevel()

    def setZoomLevel(self, level):
        self._webView.setZoomLevel(level)

    def detach(self):
        assert(self._window)
        assert(self._tabBar)

        # Remove from tab tree
        self.removeFromTabTree()

        # Remove icon from tab
        self._tabBar.setTabButton(self.tabIndex(), self._tabBar.iconButtonPosition(), None)
        self._tabIcon.setParent(self)

        # Remove the tab from tabbar
        self._window.tabWidget().removeTab(self.tabIndex())
        self.setParent(None)
        # Remove the locationbar from window
        self._locationBar.setParent(self)
        # Detach TabbedWindow
        self._webView.setBrowserWindow(None)

        if self._isCurrentTab:
            self._isCurrentTab = False
            self.currentTabChanged.emit(self._isCurrentTab)

        self._tabBar.currentChanged.disconnect(self.onCurrentChanged)

        self._window = None
        self._tabBar = None

    def onCurrentChanged(self, index):
        wasCurrent = self._isCurrentTab
        self._isCurrentTab = index == self.tabIndex()
        if wasCurrent != self._isCurrentTab:
            self.currentTabChanged.emit(self._isCurrentTab)

    def attach(self, window):
        self._window = window
        self._tabBar = self._window.tabWidget().tabBar()

        self._webView.setBrowserWindow(self._window)
        self._locationBar.setBrowserWindow(self._window)
        self._tabBar.setTabText(self.tabIndex(), self.title())
        self._tabBar.setTabButton(self.tabIndex(), self._tabBar.iconButtonPosition(), self._tabIcon)
        QTimer.singleShot(0, self._tabIcon.updateIcon)

        self.onCurrentChanged(self._tabBar.currentIndex())
        self._tabBar.currentChanged.connect(self.onCurrentChanged)

    def historyData(self):
        '''
        @return QByteArray
        '''
        if self.isRestored():
            historyArray = QByteArray()
            stream = QDataStream(historyArray, QIODevice.WriteOnly)
            history = self._webView.history()
            stream << history
            return historyArray
        else:
            return self._savedTab.history

    def stop(self):
        self._webView.stop()

    def reload(self):
        self._webView.reload()

    def load(self, request):
        '''
        @param: requset LoadRequest
        '''
        if self.isRestored():
            self.tabActivated()
            QTimer.singleShot(0, lambda: self.load(request))
        else:
            self._webView.load(request)

    def unload(self):
        self._savedTab = self.SavedTab(self)
        self.restoredChanged.emit(self.isRestored())
        self._webView.setPage(WebPage())
        self._webView.setFocus()

    def isLoading(self):
        return self._webView.isloading()

    def isPinned(self):
        return self._isPinned

    def setPinned(self, state):
        if self._isPinned == state:
            return
        if state:
            self.removeFromTabTree()
        self._isPinned = state
        self.pinnedChanged.emit(self._isPinned)

    def togglePinned(self):
        assert(self._tabBar)
        assert(self._window)
        self.setPinned(not self.isPinned())
        self._window.tabWidget().pinUnPinTab(self.tabIndex(), self.title())

    def isMuted(self):
        return self._webView.page().isAudioMuted()

    def isPlaying(self):
        return self._webView.page().recentlyAudible()

    def setMuted(self, muted):
        self._webView.page().setAudioMuted(muted)

    def toggleMuted(self):
        self.setMuted(not self.isMuted())

    def backgroundActivity(self):
        return self._webView.backgroundActivity()

    def tabIndex(self):
        index = -1
        if self._tabBar:
            index = self._tabBar.tabWidget().indexOf(self)
        return index

    def isCurrentTab(self):
        return self._isCurrentTab

    def makeCurrentTab(self):
        if self._tabBar:
            self._tabBar.tabWidget().setCurrentIndex(self.tabIndex())

    def closeTab(self):
        if self._tabBar:
            self._tabBar.tabWidget().closeTab(self.tabIndex())

    def moveTab(self, to):
        if self._tabBar:
            self._tabBar.tabWidget().moveTab(self.tabIndex(), to)

    def haveInspector(self):
        return self._splitter.count() > 1 and self._splitter.widget(1).inherits('WebInspector')

    def showWebInspector(self, inspectElement=False):
        if not WebInspector.isEnabled() or self.haveInspector():
            return

        inspector = WebInspector(self)
        inspector.setView(self._webView)
        if inspectElement:
            inspector.inspectElement()

        height = inspector.sizeHint().height()
        self._splitter.addWidget(inspector)
        self._splitter.setSizes((self._splitter.height() - height, height))

    def toggleWebInspector(self):
        if not self.haveInspector():
            self.showWebInspector()
        else:
            self._splitter.widget(1).destroy()  # TODO: del?

    def showSearchToolBar(self, searchText=''):
        index = 1
        toolBar = None
        if self._layout.count() == 1:
            toolBar = SearchToolBar(self._webView, self)
            self._layout.insertWidget(index, toolBar)
        if self._layout.count() == 2:
            assert(isinstance(self._layout.itemAt(index).widget(), SearchToolBar))
            toolBar = self._layout.itemAt(index).widget()
        assert(toolBar)
        if not searchText:
            toolBar.setText(searchText)
        toolBar.focusSearchLine()

    def isRestored(self):
        return not self._savedTab.isValid()

    def restoreTab(self, tab):
        '''
        @param: tab SavedTab
        '''
        assert(self._tabBar)
        self.setPinned(tab.isPinned)
        self._sessionData = tab.sessionData

        if not self.isPinned() and gVar.appSettings.loadTabsOnActivation:
            self._savedTab = tab
            self.restoredChanged.emit(self.isRestored())
            index = self.tabIndex()

            self._tabBar.setTabText(index, tab.title)
            self._locationBar.showUrl(tab.url)
            self._tabIcon.updateIcon()
        else:
            # This is called only on restore session and restoring tabs
            # immediately crashes QtWebEngine, waiting after initialization is
            # complete fixes it
            QTimer.singleShot(1000, lambda: self.p_restoreTab(tab))

    def p_restoreTab(self, tab):
        '''
        @param: tab SavedTab
        '''
        self.p_restoreTabByUrl(tab.url, tab.history, tab.zoomLevel)

    def p_restoreTabByUrl(self, url, history, zoomLevel):
        self._webView.load(url)

        # Restoring history of internal pages crashes QtWebEngine 5.8
        blacklistedSchemes = ['view-source', 'chrome']

        if (url.scheme() not in blacklistedSchemes):
            stream = QDataStream(history)
            stream >> self._webView.history()

        self._webView.setZoomLevel(zoomLevel)
        self._webView.setFocus()

    def tabActivated(self):
        if self.isRestored():
            return

        def _onTabActivated():
            if self.isRestored():
                return
            self.p_restoreTab(self._savedTab)
            self._savedTab.clear()
            self.restoredChanged.emit(self.isRestored())

        QTimer.singleShot(0, _onTabActivated)

    def addChildBehavior(self):
        '''
        @return AddChildBehavior
        '''
        return self.s_addChildBehavior

    def setAddChildBehavior(self, behavior):
        self.s_addChildBehavior = behavior

    # Q_SLOTS
    @pyqtSlot(QWidget)
    def showNotification(self, notif):
        self._notificationWidget.setParent(self)
        self._notificationWidget.raise_()
        self._notificationWidget.setFixedWidth(self.width())
        self._notificationWidget.layout().addWidget(notif)
        self._notificationWidget.show()
        notif.show()

    @pyqtSlot()
    def loadFinished(self):
        self.titleWasChanged(self._webView.title())

    # Q_SIGNALS
    titleChanged = pyqtSignal(str) # title
    iconChanged = pyqtSignal(QIcon) # icon
    pinnedChanged = pyqtSignal(bool) # pinned
    restoredChanged = pyqtSignal(bool) # restored
    currentTabChanged = pyqtSignal(bool) # current
    loadingChanged = pyqtSignal(bool) # loading
    mutedChanged = pyqtSignal(bool) # muted
    playingChanged = pyqtSignal(bool) # playing
    backgroundActivityChanged = pyqtSignal(bool) # activity
    parentTabChanged = pyqtSignal('PyQt_PyObject') # WebTab*
    childTabAdded = pyqtSignal('PyQt_PyObject', int) # WebTab*, index
    childTabRemoved = pyqtSignal('PyQt_PyObject', int) # WebTab*, index

    def titleWasChanged(self, title):
        if not self._tabBar or not self._window or not title:
            return
        if self._isCurrentTab:
            self._window.setWindowTitle('%s - Demo' % title)
        self._tabBar.setTabText(self.tabIndex(), title)

    # override
    def resizeEvent(self, event):
        QWidget.resizeEvent(self, event)
        self._notificationWidget.setFixedWidth(self.width())

    def removeFromTabTree(self):
        parentTab = self._parentTab
        parentIndex = -1
        if parentTab:
            parentIndex = parentTab._childTabs.index(self)
        self.setParentTab(None)

        idx = 0
        while self._childTabs:
            child = self._childTabs[0]
            child.setParentTab(None)
            if parentTab:
                parentTab.addChildTab(child, parentIndex + idx)
                idx += 1
Esempio n. 14
0
class MainWindow(QMainWindow):

    KEY_WINDOW_SIZE = 'main_window/size'
    KEY_WINDOW_MAXIMIZED = 'main_window/maximized'
    KEY_WINDOW_POSITION = 'main_window/position'
    KEY_H_SPLITTER_STATE = 'main_window/h_splitter_state'

    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle('Mojuru')
        app_icon = QIcon('images/mojuru_logo.png')
        self.setWindowIcon(app_icon)

        reload_modules_action = QAction('Reload MainWindow', self)
        reload_modules_action.setShortcut('ctrl+shift+alt+r')
        reload_modules_action.triggered.connect(self.reload_central_widget)
        self.addAction(reload_modules_action)

        quit_action = QAction('Quit', self)
        quit_action.setShortcut('ctrl+q')
        quit_action.triggered.connect(self.on_quit)
        self.addAction(quit_action)

        self.vertical_splitter = QSplitter(Qt.Vertical, self)
        self.setCentralWidget(self.vertical_splitter)
        self.load_central_widget()

        self.file_menu = self.menuBar().addMenu(self.tr('&File'))
        self.file_menu.addAction(quit_action)
        self.file_menu.addSeparator()

        self.module_menu = self.menuBar().addMenu(self.tr('&Modules'))
        self.module_menu.addAction(reload_modules_action)
        self.module_menu.addSeparator()

        Alter.invoke_all('main_window_init', self)

        #restore main window state
        size = ModuleManager.core['settings'].Settings.value(
            self.KEY_WINDOW_SIZE, QSize(600, 400))
        maximized = ModuleManager.core['settings'].Settings.value(
            self.KEY_WINDOW_MAXIMIZED, False)
        position = ModuleManager.core['settings'].Settings.value(
            self.KEY_WINDOW_POSITION, QPoint(0, 0))
        if maximized == 'true':
            self.showMaximized()
        else:
            self.resize(size)
            self.move(position)

    def closeEvent(self, event):
        self.on_quit()

    def save_state(self):
        ModuleManager.core['settings'].Settings.set_value(
            self.KEY_WINDOW_SIZE, self.size())
        ModuleManager.core['settings'].Settings.set_value(
            self.KEY_WINDOW_MAXIMIZED, self.isMaximized())
        ModuleManager.core['settings'].Settings.set_value(
            self.KEY_WINDOW_POSITION, self.pos())
        ModuleManager.core['settings'].Settings.set_value(
            self.KEY_H_SPLITTER_STATE, self.horizontal_splitter.saveState())

    def on_quit(self):
        self.save_state()
        self.close()

    def load_central_widget(self):
        self.populate_central_widget()
        self.connect_widgets()

    def populate_central_widget(self):
        self.vertical_widgets = collections.OrderedDict()

        self.horizontal_splitter = QSplitter(Qt.Horizontal,
                                             self.vertical_splitter)
        self.horizontal_widgets = collections.OrderedDict()
        self.vertical_widgets["horizontal_splitter"] = self.horizontal_splitter

        Alter.invoke_all('main_window_add_vertical_widget',
                         self.vertical_widgets, self)
        for widget in self.vertical_widgets.values():
            self.vertical_splitter.addWidget(widget)

        Alter.invoke_all('main_window_add_horizontal_widget',
                         self.horizontal_widgets, self.vertical_splitter)
        for widget in self.horizontal_widgets.values():
            self.horizontal_splitter.addWidget(widget)

        #restore horizontal splitter state
        state = ModuleManager.core['settings'].Settings.value(
            self.KEY_H_SPLITTER_STATE, None)
        if state:
            self.horizontal_splitter.restoreState(state)

    def connect_widgets(self):
        Alter.invoke_all('main_window_connect_widgets', self.vertical_widgets,
                         self.horizontal_widgets)

    def reload_central_widget(self):
        self.save_state()
        for index in range(self.vertical_splitter.count()):
            widget = self.vertical_splitter.widget(index)
            widget.hide()
            widget.setParent(None)
            del widget
        Alter.clear()
        ModuleManager.reload_all_modules('core')
        ModuleManager.reload_all_modules('custom')
        self.load_central_widget()
Esempio n. 15
0
class DanaBrowseWindow(QMainWindow):
    def __init__(self, args):
        super(DanaBrowseWindow, self).__init__()
        #Leeo la configuracion
        self.configFile = args.configFile
        self.secure = args.secure
        self.cubeFile = args.cubeFile
        self.sysExclude = args.sysExclude

        self.maxLevel = 1  #para poder modificarlo luego
        self.dictionary = DataDict(defFile=args.configFile,
                                   secure=args.secure,
                                   sysExclude=args.sysExclude)
        #TODO variables asociadas del diccionario. Reevaluar al limpiar

        self.baseModel = self.dictionary.baseModel
        self.configData = self.dictionary.configData
        self.conn = self.dictionary.conn
        if self.dictionary.isEmpty:
            self.newConfigData()
            #self.dictionary._cargaModelo(self.dictionary.baseModel)
        self.setupView()
        self.cubeMgr = None  # necesito mas adelante que este definida
        if config.DEBUG:
            print('inicializacion completa')
        #CHANGE here

        self.queryView = TableBrowse(None)

        self.dictMenu = self.menuBar().addMenu("&Conexiones")
        self.dictMenu.addAction("&New ...", self.newConnection, "Ctrl+N")
        self.dictMenu.addAction("&Modify ...", self.modConnection, "Ctrl+M")
        self.dictMenu.addAction("&Delete ...", self.delConnection, "Ctrl+D")
        self.dictMenu.addAction("&Save Config File", self.saveConfigFile,
                                "Ctrl+S")
        self.dictMenu.addAction("E&xit", self.close, "Ctrl+Q")

        self.queryMenu = self.menuBar().addMenu('Consulta de &datos')
        self.queryMenu.addAction("Cerrar", self.hideDatabrowse)
        self.queryMenu.setEnabled(False)

        self.cubeMenu = self.menuBar().addMenu("C&ubo")
        self.cubeMenu.addAction("&Salvar", self.saveCubeFile, "Ctrl+S")
        #self.cubeMenu.addAction("&Restaurar", self.restoreCubeFile, "Ctrl+M")
        self.cubeMenu.addAction("S&alir", self.hideCube, "Ctrl+C")
        self.cubeMenu.addSeparator()
        self.cubeMenu.addAction("Ver &ejemplo de datos del cubo",
                                self.previewCube, "Ctrl+E")
        self.cubeMenu.setEnabled(False)

        #self.queryModel = self.queryView.baseModel

        self.querySplitter = QSplitter(Qt.Vertical)
        self.querySplitter.addWidget(self.view)
        #self.querySplitter.addWidget(self.queryView)

        self.configSplitter = QSplitter(Qt.Horizontal)
        self.configSplitter.addWidget(self.querySplitter)

        self.setCentralWidget(self.configSplitter)

        self.setWindowTitle("Visualizador de base de datos")
        """
            estas funciones son para soportar para los decoradores keep position y tal
        """

    def model(self):
        return self.baseModel

    def isExpanded(self, idx):
        return self.view.isExpanded(idx)

    def setExpanded(self, idx, state):
        return self.view.setExpanded(idx, state)

    def setupView(self):
        self.view = QTreeView(self)
        self.view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.view.customContextMenuRequested.connect(self.openContextMenu)
        self.view.doubleClicked.connect(self.test)
        self.view.setModel(self.baseModel)
        #self.view.resizeColumnToContents(0)
        self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)

        self.view.expandAll()
        for m in range(self.baseModel.columnCount()):
            self.view.resizeColumnToContents(m)
        self.view.collapseAll()
        self.view.expandToDepth(0)
        #self.view.setHeaderHidden(True)
        #self.view.setSortingEnabled(True)
        #self.view.setRootIsDecorated(False)
        self.view.setAlternatingRowColors(True)
        #self.view.sortByColumn(0, Qt.AscendingOrder)

    def newConfigData(self):
        self.configData = dict()
        self.configData['Conexiones'] = dict()
        self.editConnection(None)
        if self.configData['Conexiones']:
            self.saveConfigFile()
            print(self.configData)
            self.dictionary._cargaModelo(confData=self.configData['Conexiones']
                                         )  #self.dictionary.baseModel)
        else:
            QMessageBox.critical(
                self, "Error Fatal",
                "No se ha encontrado una conexión valida.\nFin de proceso")
            self.close()

    def saveConfigFile(self):
        dump_config(self.configData,
                    getConfigFileName(self.configFile),
                    secure=self.secure)  #TODO de momento

    def closeEvent(self, event):
        self.close()

    def close(self):

        if self.cubeMgr:
            self.saveConfigFile()

        for conid in self.conn:
            if self.conn[conid] is None:
                continue
            if self.conn[conid].closed:
                self.conn[conid].close()
        self.saveConfigFile()

        sys.exit()

    def newConnection(self):
        confName = self.editConnection(None)
        # esta claro que sobran parametros
        self.dictionary.appendConnection(confName)

    def modConnection(self, nombre=None):
        if nombre is None:
            selDialog = SelectConnectionDlg(self.configData['Conexiones'])
            if selDialog.exec_():
                confName = selDialog.conexion
            else:
                return
        else:
            confName = nombre
        self.editConnection(confName)
        self.updateModel(confName)

    @waiting_effects
    def updateModel(self, nombre=None):
        self.dictionary.updateModel(nombre)

    def delConnection(self, nombre=None):
        if nombre is None:
            selDialog = SelectConnectionDlg(self.configData['Conexiones'])
            if selDialog.exec_():
                confName = selDialog.conexion
            else:
                return
        else:
            confName = nombre
        self.dictionary.dropConnection(confName)

    def editConnection(self, nombre=None):
        attr_list = ('driver', 'dbname', 'dbhost', 'dbuser', 'dbpass',
                     'dbport', 'debug')
        if nombre is None:
            datos = [None for k in range(len(attr_list) + 1)]
        else:
            datos = [
                nombre,
            ] + dict2row(self.configData['Conexiones'][nombre], attr_list)
            datos[1] = DRIVERS.index(datos[1])
        #contexto
        context = (
            (
                'Nombre',
                QLineEdit,
                {
                    'setReadOnly': True
                } if nombre is not None else None,
                None,
            ),
            # driver
            (
                "Driver ",
                QComboBox,
                None,
                DRIVERS,
            ),
            (
                "DataBase Name",
                QLineEdit,
                None,
                None,
            ),
            (
                "Host",
                QLineEdit,
                None,
                None,
            ),
            (
                "User",
                QLineEdit,
                None,
                None,
            ),
            (
                "Password",
                QLineEdit,
                {
                    'setEchoMode': QLineEdit.Password
                },
                None,
            ),
            (
                "Port",
                QLineEdit,
                None,
                None,
            ),
            (
                "Debug",
                QCheckBox,
                None,
                None,
            ))
        parmDialog = ConnectionSheetDlg('Edite la conexion', context, datos,
                                        self)
        if parmDialog.exec_():
            #TODO deberia verificar que se han cambiado los datos
            #datos[1]=DRIVERS[datos[1]]
            self.configData['Conexiones'][datos[0]] = row2dict(
                datos[1:], attr_list)
            return datos[0]

    @keep_tree_layout()
    def openContextMenu(self, position):
        """
        """
        item = None
        indexes = self.view.selectedIndexes()
        if len(indexes) > 0:
            index = indexes[0]
            item = self.baseModel.itemFromIndex(index)
        menu = QMenu()
        if item:
            item.setMenuActions(menu, self)
            action = menu.exec_(self.view.viewport().mapToGlobal(position))
        #getContextMenu(item,action,self)

    @waiting_effects
    def databrowse(self, confName, schema, table, iters=0):
        #print(confName,schema,table,self.dictionary.conn[confName])
        self.queryView.reconnect(
            self.queryView.getConnection(self.dictionary, confName, schema,
                                         table, iters))
        self.queryView.executeNewScript(
            self.queryView.generateSQL(confName,
                                       schema,
                                       table,
                                       iters,
                                       pFilter=None))
        if self.queryView.isHidden():
            self.queryView.show()
        self.queryMenu.setEnabled(True)
        if self.querySplitter.count(
        ) == 1:  #de momento parece un modo sencillo de no multiplicar en exceso
            self.querySplitter.addWidget(self.queryView)

    def hideDatabrowse(self):
        self.queryView.hide()
        self.queryMenu.setEnabled(False)

    def prepareNewCube(self, confName, schema, table):
        # aqui tiene que venir un dialogo para seleccionar nombre del cubo
        maxLevel = self.maxLevel
        parmDlg = GenerationSheetDlg('Parámetros de generación', table,
                                     maxLevel)
        if parmDlg.exec_():
            kname = parmDlg.data[0]
            maxLevel = parmDlg.data[1]
        infox = info2cube(self.dictionary, confName, schema, table, maxLevel)
        if kname != table:
            infox[kname] = infox.pop(table)
        return infox

    def cubebrowse(self, confName, schema, table):

        infox = self.prepareNewCube(confName, schema, table)
        if self.cubeMgr and not self.cubeMgr.isHidden():
            self.hideCube()
        self.cubeMgr = CubeMgr(self,
                               confName,
                               schema,
                               table,
                               self.dictionary,
                               rawCube=infox,
                               cubeFile=self.cubeFile)
        self.cubeMgr.expandToDepth(1)
        #if self.configSplitter.count() == 1:  #de momento parece un modo sencillo de no multiplicar en exceso
        self.configSplitter.addWidget(self.cubeMgr)

        self.cubeMgr.show()
        self.cubeMenu.setEnabled(True)

    def saveCubeFile(self):
        self.cubeMgr.saveCubeFile()

    def restoreCubeFile(self):
        self.cubeMgr.restoreConfigFile()

    def hideCube(self):
        self.cubeMgr.saveCubeFile()
        self.cubeMgr.hide()
        self.cubeMenu.setEnabled(False)

    def test(self, index):
        return
        print(index.row(), index.column())
        item = self.baseModel.itemFromIndex(index)
        print(item.text(), item.model())

    def refreshTable(self):
        self.baseModel.emitModelReset()

    def previewCube(self):
        startItem = self.cubeMgr.model().item(0, 0)
        conName = self.cubeMgr.defaultConnection
        self.queryView.reconnect(
            self.queryView.getConnection(self.dictionary, confName=conName))
        query = self.cubeMgr.getPreviewQuery(startItem)
        self.queryView.executeNewScript(query)
        if self.queryView.isHidden():
            self.queryView.show()
        self.queryMenu.setEnabled(True)
        if self.querySplitter.count(
        ) == 1:  #de momento parece un modo sencillo de no multiplicar en exceso
            self.querySplitter.addWidget(self.queryView)