Beispiel #1
0
class PyMultiPageWidget(QWidget):
    def __init__(self, parent=None):
        super(PyMultiPageWidget, self).__init__(parent)
        self.value = 0

        self.bt = QPushButton('switch', self)
        self.bt.clicked.connect(self.switch)

        self.stackWidget = QStackedWidget()
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.bt)
        self.layout.addWidget(self.stackWidget)
        self.setLayout(self.layout)
        self.resize(500, 400)

    def switch(self):
        self.value = 1 - self.value
        bt = QPushButton('new')
        if self.value:
            self.addPage(bt)
        else:
            self.removePage(0)

    @pyqtSlot(QWidget)
    def addPage(self, page):
        index = self.stackWidget.count()
        page.setParent(self.stackWidget)
        self.stackWidget.insertWidget(index, page)

    @pyqtSlot(int)
    def removePage(self, index):
        widget = self.stackWidget.widget(index)
        self.stackWidget.removeWidget(widget)
Beispiel #2
0
class IPFSHashExplorerStack(GalacteekTab):
    """
    Organizes IPFSHashExplorerWidgets with a QStackedWidget
    """
    def __init__(self, gWindow, hashRef, maxItems=16, parent=None):
        super(IPFSHashExplorerStack, self).__init__(gWindow)

        self.rootHash = hashRef
        self.maxItems = maxItems

        self.stack = QStackedWidget(self)
        self.exLayout = QVBoxLayout()
        self.exLayout.addWidget(self.stack)

        self.vLayout.addLayout(self.exLayout)
        if self.rootHash:
            self.viewHash(self.rootHash)

    def tabDestroyedPost(self):
        self.stack.setParent(None)
        self.stack.deleteLater()

    @property
    def itemsCount(self):
        return self.stack.count()

    def viewHash(self,
                 hashRef,
                 addClose=False,
                 autoOpenFolders=False,
                 parentView=None):
        view = IPFSHashExplorerWidget(hashRef,
                                      parent=self,
                                      addClose=addClose,
                                      showCidLabel=True,
                                      autoOpenFolders=autoOpenFolders,
                                      parentView=parentView)
        view.closeRequest.connect(partialEnsure(self.remove, view))
        view.directoryOpenRequest.connect(lambda nView, cid: self.viewHash(
            cid, addClose=True, parentView=nView))

        self.stack.insertWidget(self.stack.count(), view)
        self.stack.setCurrentWidget(view)
        view.reFocus()
        return True

    async def remove(self, view):
        try:
            view.cancelTasks()
            self.stack.removeWidget(view)
        except:
            pass

    async def onClose(self):
        for idx in range(self.stack.count()):
            widget = self.stack.widget(idx)
            await widget.cleanup()

        return True
Beispiel #3
0
class Root(QMainWindow):
    task_list_index = 0
    task_view_index = 1

    def __init__(self):
        super().__init__()
        self.model = None
        self.task_view = None
        self.initUI()

    def initUI(self):
        # self.cal = QCalendarWidget(self)
        # self.cal.setVerticalHeaderFormat(QCalendarWidget.NoVerticalHeader)
        # self.cal.setGeometry(0, 0, 250, 250)

        self.model = TaskModel()
        self.central = QStackedWidget()

        task_list = TaskList(self.model)
        task_list.open.connect(self.task_open)
        self.central.insertWidget(Root.task_list_index, task_list)

        self.task_view = TaskView(self.model)
        self.task_view.close.connect(self.task_view_close)
        self.central.insertWidget(Root.task_view_index, self.task_view)

        self.central.setCurrentIndex(Root.task_list_index)
        self.setCentralWidget(self.central)

        # QDialog flags:
        #   Qt.Dialog |
        #   Qt.WindowTitleHint |
        #   Qt.WindowSystemMenuHint |
        #   Qt.WindowContextHelpButtonHint |
        #   Qt.WindowCloseButtonHint
        self.setWindowFlags(Qt.Dialog | Qt.WindowStaysOnTopHint)
        self.setGeometry(700, 300, 250, 300)
        self.setWindowTitle('Calendar')

    @pyqtSlot(int)
    def task_open(self, index):
        self.task_view.set_task(index)
        self.central.setCurrentIndex(Root.task_view_index)

    @pyqtSlot()
    def task_view_close(self):
        self.central.setCurrentIndex(Root.task_list_index)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.close()
Beispiel #4
0
class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
        self.stacked_widget.currentChanged.connect(self.set_button_state)
        self.next_button.clicked.connect(self.next_page)
        self.prev_button.clicked.connect(self.prev_page)


    def initUI(self):

        self.next_button = QPushButton('Next')
        self.prev_button = QPushButton('Previous')
        self.next_button.setEnabled(False)
        self.prev_button.setEnabled(False)
        self.stacked_widget = QStackedWidget()

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.prev_button)
        hbox.addWidget(self.next_button)

        vbox = QVBoxLayout()
        vbox.addWidget(self.stacked_widget)
        vbox.addLayout(hbox)

        self.setLayout(vbox)


    def set_button_state(self, index):
        self.prev_button.setEnabled(index > 0)
        n_pages = len(self.stacked_widget)
        self.next_button.setEnabled( index % n_pages < n_pages - 1)

    def insert_page(self, widget, index=-1):
        self.stacked_widget.insertWidget(index, widget)
        self.set_button_state(self.stacked_widget.currentIndex())

    def next_page(self):
        new_index = self.stacked_widget.currentIndex()+1
        if new_index < len(self.stacked_widget):
            self.stacked_widget.setCurrentIndex(new_index)

    def prev_page(self):
        new_index = self.stacked_widget.currentIndex()-1
        if new_index >= 0:
            self.stacked_widget.setCurrentIndex(new_index)
Beispiel #5
0
class Demo(QWidget):
    def __init__(self, parent=None, *args, **kwargs):
        super(Demo, self).__init__(parent, *args, **kwargs)
        # 整体水平盒子布局
        self.hbox = QHBoxLayout()
        self.setLayout(self.hbox)

        self.vbox = QVBoxLayout()
        self.stacked = QStackedWidget()

        self.hbox.addLayout(self.vbox)
        self.hbox.addWidget(self.stacked)

        self.btn1 = QPushButton('btn1')
        self.btn2 = QPushButton('btn2')
        self.btn3 = QPushButton('btn3')
        self.btn1.setObjectName('btn1')
        self.btn2.setObjectName('btn2')
        self.btn3.setObjectName('btn3')

        self.vbox.addWidget(self.btn1)
        self.vbox.addWidget(self.btn2)
        self.vbox.addWidget(self.btn3)

        self.lab1 = QLabel('页面1')
        self.lab2 = QLabel('页面2')
        self.lab3 = QLabel('页面3')
        self.stacked.insertWidget(0, self.lab1)
        self.stacked.insertWidget(1, self.lab2)
        self.stacked.insertWidget(2, self.lab3)

        QMetaObject.connectSlotsByName(self)

    @pyqtSlot()
    def on_btn1_clicked(self):
        self.stacked.setCurrentIndex(0)

    @pyqtSlot()
    def on_btn2_clicked(self):
        self.stacked.setCurrentIndex(1)

    @pyqtSlot()
    def on_btn3_clicked(self):
        self.stacked.setCurrentIndex(2)
Beispiel #6
0
class IPFSHashExplorerStack(GalacteekTab):
    """
    Organizes IPFSHashExplorerWidgets with a QStackedWidget
    """
    def __init__(self, gWindow, hashRef, maxItems=16, parent=None):
        super(IPFSHashExplorerStack, self).__init__(gWindow)

        self.rootHash = hashRef
        self.maxItems = maxItems

        self.stack = QStackedWidget(self)
        self.exLayout = QVBoxLayout()
        self.exLayout.addWidget(self.stack)

        self.vLayout.addLayout(self.exLayout)
        if self.rootHash:
            self.viewHash(self.rootHash)

    @property
    def itemsCount(self):
        return self.stack.count()

    def viewHash(self, hashRef, addClose=False, autoOpenFolders=False):
        view = IPFSHashExplorerWidget(hashRef,
                                      parent=self,
                                      addClose=addClose,
                                      showCidLabel=True,
                                      autoOpenFolders=autoOpenFolders)
        view.closeRequest.connect(functools.partial(self.remove, view))
        view.directoryOpenRequest.connect(
            lambda cid: self.viewHash(cid, addClose=True))

        self.stack.insertWidget(self.stack.count(), view)
        self.stack.setCurrentWidget(view)
        view.reFocus()
        return True

    def remove(self, view):
        try:
            self.stack.removeWidget(view)
        except:
            pass
class Timer(Base):

    def __init__(self, observer: Observer, name: str, foreground_color="#ffffff", font_name=""):
        super().__init__(name, foreground_color, font_name)

        self.main_layout = QGridLayout()
        self.central_widget = QStackedWidget()
        self.central_widget.insertWidget(0, TimerOverview(observer, "TimerOverview", self, foreground_color))
        self.central_widget.insertWidget(1, AddTimer(observer, "AddTimer", self, foreground_color))
        self.central_widget.setCurrentIndex(0)

        self.main_layout.addWidget(self.central_widget)
        self.setLayout(self.main_layout)

    def pass_timer(self, timer_config: dict):
        self.central_widget.widget(0).add_timer(timer_config)

    def switch_central_widget(self):
        max_value = self.central_widget.count()
        index = self.central_widget.currentIndex()
        self.central_widget.setCurrentIndex((index + 1) % max_value)
Beispiel #8
0
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        layout = QVBoxLayout()
        self.stackedWidget = QStackedWidget()
        self.stackedWidget.addWidget(ClockPanel())
        self.alarms_panel = AlarmsPanel()
        self.stackedWidget.addWidget(self.alarms_panel)
        self.stackedWidget.addWidget(SettingsPanel())
        layout.addWidget(self.stackedWidget)

        menu_buttons = MenuButtons()
        menu_buttons.switch_panel.connect(self.switch_panel)
        layout.addWidget(menu_buttons)

        self.alarms_panel.edit_alarms.connect(self.display_edit_alarm)

        self.setLayout(layout)

    @pyqtSlot(int, name="switch_panel")
    def switch_panel(self, panel_index):
        self.stackedWidget.setCurrentIndex(panel_index)

    @pyqtSlot(int, name="edit_alarm")
    def display_edit_alarm(self, alarm_id):
        print('EDIT ' + str(alarm_id))
        # drop alarms panel
        edit_alarm_panel = EditAlarmPanel(alarm_id)
        self.stackedWidget.insertWidget(1, edit_alarm_panel)
        self.stackedWidget.setCurrentIndex(1)
        self.stackedWidget.removeWidget(self.alarms_panel)
        # display edit alarm panel

        edit_alarm_panel.quit_signal.connect(self.hello)

    @pyqtSlot(name="quit")
    def hello(self):
        print('should close the edit alarm panel')
Beispiel #9
0
class MainArea(QWidget):
    """A class responsible for organizing artist/album/playlist/now playing tabs
    and generally access to library contents."""

    def __init__(self, control, upperBox: UpperBox) -> None:
        super().__init__()
        self.control = control
        self.songListArea = upperBox.songList
        self.layout = QVBoxLayout()
        self.buttons = QWidget()
        self.setLayout(self.layout)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.addWidget(self.buttons)
        self.buttonLayout = QHBoxLayout()
        self.labels = {"Artists": QPushButton(), "Albums": QPushButton(),
                       "Playlists": QPushButton(), "Now Playing": QPushButton()}
        self.setButtons()
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        self.layout.addWidget(line)
        self.mainArea = QStackedWidget()
        self.layout.addWidget(self.mainArea)

        self.artistScrollArea = MainScrollArea(FlowLayout)
        self.artistLayout = self.artistScrollArea.widget().layout()
        self.mainArea.insertWidget(0, self.artistScrollArea)

        self.albumScrollArea = MainScrollArea(FlowLayout)
        self.albumLayout = self.albumScrollArea.widget().layout()
        self.mainArea.insertWidget(1, self.albumScrollArea)

        self.playlistScrollArea = MainScrollArea(FlowLayout)
        self.playlistLayout = self.playlistScrollArea.widget().layout()
        self.mainArea.insertWidget(2, self.playlistScrollArea)

        self.nowPlayingScrollArea = MainScrollArea(QGridLayout)
        self.nowPlayingLayout = self.nowPlayingScrollArea.widget().layout()
        self.nowPlayingLayout.setAlignment(Qt.AlignTop)
        self.nowPlayingLayout.setHorizontalSpacing(0)
        self.nowPlayingLayout.setVerticalSpacing(0)
        self.nowPlayingLayout.setContentsMargins(0, 0, 0, 0)
        self.nowPlayingLayout.setColumnStretch(0, 1)
        self.nowPlayingLayout.setColumnStretch(1, 1)
        self.nowPlayingLayout.setColumnStretch(3, 2)
        self.mainArea.insertWidget(3, self.nowPlayingScrollArea)

        self.nowPlayingSong = None
        self.garbageProtector = {}

        self.pixmaps = {"artist": artistPixmap,
                        "album": albumPixmap,
                        "playlist": playlistPixmap}

        self.activePixmaps = []
        self.index = 0
        for n in range(1, 8):
            self.activePixmaps.append(QPixmap(f"{location}active{n}.png"))

        for scrollArea in [self.artistScrollArea, self.albumScrollArea,
                           self.playlistScrollArea, self.nowPlayingScrollArea]:
            scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
            scrollArea.setWidgetResizable(True)
            scrollArea.setFrameShape(QFrame.NoFrame)

    def setButtons(self) -> None:
        """Creates buttons for switching between tabs."""
        self.buttonLayout.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.buttonLayout.setSpacing(20)
        self.buttons.setLayout(self.buttonLayout)
        self.buttons.setFixedHeight(45)
        for label in self.labels:
            button = self.labels[label]
            button.setText(label)
            font = QFont()
            font.setBold(True)
            font.setPointSize(12)
            button.setFont(font)
            button.setStyleSheet("color:#afafaf;"
                                 "text-align:top;"
                                 "border-style: none;"
                                 "background-color:#141414;")
            button.setFixedHeight(25)
            self.buttonLayout.addWidget(button)
        self.labels["Artists"].clicked.connect(lambda x: self.showArea(0))
        self.labels["Albums"].clicked.connect(lambda x: self.showArea(1))
        self.labels["Playlists"].clicked.connect(lambda x: self.showArea(2))
        self.labels["Now Playing"].clicked.connect(lambda x: self.showArea(3))

    def setAreas(self, library) -> None:
        """Called after the GUI has been shown, draws widgets for all
        artists/albums/playlists in the library."""
        self.setMainAreaArtists(library)
        self.setMainAreaAlbums(library)
        self.setMainAreaPlaylists(library)
        self.setNowPlayingArea(library)

    def updateView(self, library) -> None:
        areas = {self.artistLayout: library.artists,
                 self.albumLayout: library.albums,
                 self.playlistLayout: library.playlists}
        types = {self.artistLayout: "artist",
                 self.albumLayout: "album",
                 self.playlistLayout: "playlist"}
        for area in areas:
            fieldNames = []
            toBeRemoved = []
            for field in area.items:
                fieldNames.append(field.widget().name)
                if field.widget().name not in areas[area]:
                    toBeRemoved.append(field)
            if len(toBeRemoved):
                for field in toBeRemoved:
                    area.removeItem(field)
                    field.widget().hide()
                    field.widget().deleteLater()
            for libraryItem in areas[area]:
                if libraryItem not in fieldNames:
                    self.addItemToLayout(area, types[area], libraryItem)
                    fieldNames.append(libraryItem)

    def addItemToLayout(self, layout: QLayout, isType: str, name: str) -> None:
        item = MediaWidget(self.control, isType, name)
        item.setFixedSize(160, 195)
        itemLayout = QVBoxLayout()
        item.setLayout(itemLayout)
        label = QLabel()
        label.setFixedSize(150, 150)
        label.setPixmap(QPixmap(self.pixmaps[isType]))
        label.setScaledContents(True)
        itemLayout.addWidget(label)
        label = QLabel(name)
        label.setFixedWidth(150)
        label.setStyleSheet("color:#afafaf;"
                            "font-size: 12px;"
                            "font-weight: bold;")
        label.setAlignment(Qt.AlignCenter)
        label.setWordWrap(True)
        itemLayout.addWidget(label)
        layout.addWidget(item)

    def setMainAreaArtists(self, library) -> None:
        clearLayout(self.artistLayout)
        if library is not None:
            for artist in library.artists:
                self.addItemToLayout(self.artistLayout, "artist", artist)

    def setMainAreaAlbums(self, library) -> None:
        clearLayout(self.albumLayout)
        if library is not None:
            for album in library.albums:
                self.addItemToLayout(self.albumLayout, "album", album)

    def setMainAreaPlaylists(self, library) -> None:
        clearLayout(self.playlistLayout)
        if library is not None:
            for playlist in library.playlists:
                self.addItemToLayout(self.playlistLayout, "playlist", playlist)

    def setNowPlayingArea(self, library, clearOnly: bool = False) -> None:
        clearLayout(self.nowPlayingLayout)
        self.garbageProtector = {}
        self.nowPlayingSong = None
        if library is not None:
            column = 0
            row = 0
            for fieldName in ["Artist", "Album",
                              "Track", "Title", "", "Length"]:
                field = QLabel(fieldName)
                field.setStyleSheet("QWidget {"
                                    "    color:#afafaf;"
                                    "    font-size: 15px;"
                                    "    font-weight: bold;"
                                    "    border-style: none none solid none;"
                                    "    border-width: 2px;"
                                    "    border-color: #afafaf;"
                                    "}")
                self.nowPlayingLayout.addWidget(field, row, column)
                column += 1
            row += 1
            if clearOnly:
                return
            for n in range(self.control.playlist.mediaCount()):
                media = self.control.playlist.media(n)
                song = media.request().url().toLocalFile().replace("/", "\\")
                if song in library.library:
                    column = 0
                    self.garbageProtector[song] = []
                    for field in [ARTIST, ALBUM, TRACK, NAME, "pixmap",  LENGTH]:
                        songWidget = SongWidget(self.control, song, True)
                        songWidget.setLayout(QHBoxLayout())
                        songWidget.setStyleSheet("QLabel {"
                                                 "    color:#afafaf;"
                                                 "    font-size: 12px;"
                                                 "    border-style: none none solid none;"
                                                 "    border-width: 0.5px;"
                                                 "    border-color: #3c3c3c;"
                                                 "}")
                        label = QLabel()
                        if field != "pixmap":
                            label.setText(library.library[song][field])
                            if field == LENGTH:
                                label.setAlignment(Qt.AlignRight)
                        else:
                            label.setFixedSize(15, 15)
                            label.setScaledContents(True)
                        songWidget.layout().addWidget(label)
                        songWidget.layout().setContentsMargins(0, 15, 0, 0)
                        self.garbageProtector[song].append(label)
                        self.nowPlayingLayout.addWidget(songWidget, row, column)
                        column += 1
                    row += 1

    def updateActiveSong(self, currentIndex: int) -> None:
        """Shows a small image on the currently playing song for visual feedback."""
        if self.nowPlayingSong is not None:
            self.nowPlayingSong.clear()
            self.nowPlayingSong = None
        if (item := self.nowPlayingLayout.itemAtPosition(currentIndex + 1, 4)) is not None:
            label = item.widget().layout().itemAt(0).widget()
            self.nowPlayingSong = label
Beispiel #10
0
class TilesetDock(QDockWidget):
    ##
    # Emitted when the current tile changed.
    ##
    currentTileChanged = pyqtSignal(list)
    ##
    # Emitted when the currently selected tiles changed.
    ##
    stampCaptured = pyqtSignal(TileStamp)
    ##
    # Emitted when files are dropped at the tileset dock.
    ##
    tilesetsDropped = pyqtSignal(QStringList)
    newTileset = pyqtSignal()

    ##
    # Constructor.
    ##
    def __init__(self, parent=None):
        super().__init__(parent)

        # Shared tileset references because the dock wants to add new tiles
        self.mTilesets = QVector()
        self.mCurrentTilesets = QMap()
        self.mMapDocument = None
        self.mTabBar = QTabBar()
        self.mViewStack = QStackedWidget()
        self.mToolBar = QToolBar()
        self.mCurrentTile = None
        self.mCurrentTiles = None
        self.mNewTileset = QAction(self)
        self.mImportTileset = QAction(self)
        self.mExportTileset = QAction(self)
        self.mPropertiesTileset = QAction(self)
        self.mDeleteTileset = QAction(self)
        self.mEditTerrain = QAction(self)
        self.mAddTiles = QAction(self)
        self.mRemoveTiles = QAction(self)
        self.mTilesetMenuButton = TilesetMenuButton(self)
        self.mTilesetMenu = QMenu(self)  # opens on click of mTilesetMenu
        self.mTilesetActionGroup = QActionGroup(self)
        self.mTilesetMenuMapper = None  # needed due to dynamic content
        self.mEmittingStampCaptured = False
        self.mSynchronizingSelection = False

        self.setObjectName("TilesetDock")
        self.mTabBar.setMovable(True)
        self.mTabBar.setUsesScrollButtons(True)
        self.mTabBar.currentChanged.connect(self.updateActions)
        self.mTabBar.tabMoved.connect(self.moveTileset)
        w = QWidget(self)
        horizontal = QHBoxLayout()
        horizontal.setSpacing(0)
        horizontal.addWidget(self.mTabBar)
        horizontal.addWidget(self.mTilesetMenuButton)
        vertical = QVBoxLayout(w)
        vertical.setSpacing(0)
        vertical.setContentsMargins(5, 5, 5, 5)
        vertical.addLayout(horizontal)
        vertical.addWidget(self.mViewStack)
        horizontal = QHBoxLayout()
        horizontal.setSpacing(0)
        horizontal.addWidget(self.mToolBar, 1)
        vertical.addLayout(horizontal)
        self.mNewTileset.setIcon(QIcon(":images/16x16/document-new.png"))
        self.mImportTileset.setIcon(QIcon(":images/16x16/document-import.png"))
        self.mExportTileset.setIcon(QIcon(":images/16x16/document-export.png"))
        self.mPropertiesTileset.setIcon(
            QIcon(":images/16x16/document-properties.png"))
        self.mDeleteTileset.setIcon(QIcon(":images/16x16/edit-delete.png"))
        self.mEditTerrain.setIcon(QIcon(":images/16x16/terrain.png"))
        self.mAddTiles.setIcon(QIcon(":images/16x16/add.png"))
        self.mRemoveTiles.setIcon(QIcon(":images/16x16/remove.png"))
        Utils.setThemeIcon(self.mNewTileset, "document-new")
        Utils.setThemeIcon(self.mImportTileset, "document-import")
        Utils.setThemeIcon(self.mExportTileset, "document-export")
        Utils.setThemeIcon(self.mPropertiesTileset, "document-properties")
        Utils.setThemeIcon(self.mDeleteTileset, "edit-delete")
        Utils.setThemeIcon(self.mAddTiles, "add")
        Utils.setThemeIcon(self.mRemoveTiles, "remove")
        self.mNewTileset.triggered.connect(self.newTileset)
        self.mImportTileset.triggered.connect(self.importTileset)
        self.mExportTileset.triggered.connect(self.exportTileset)
        self.mPropertiesTileset.triggered.connect(self.editTilesetProperties)
        self.mDeleteTileset.triggered.connect(self.removeTileset)
        self.mEditTerrain.triggered.connect(self.editTerrain)
        self.mAddTiles.triggered.connect(self.addTiles)
        self.mRemoveTiles.triggered.connect(self.removeTiles)
        self.mToolBar.addAction(self.mNewTileset)
        self.mToolBar.setIconSize(QSize(16, 16))
        self.mToolBar.addAction(self.mImportTileset)
        self.mToolBar.addAction(self.mExportTileset)
        self.mToolBar.addAction(self.mPropertiesTileset)
        self.mToolBar.addAction(self.mDeleteTileset)
        self.mToolBar.addAction(self.mEditTerrain)
        self.mToolBar.addAction(self.mAddTiles)
        self.mToolBar.addAction(self.mRemoveTiles)
        self.mZoomable = Zoomable(self)
        self.mZoomComboBox = QComboBox()
        self.mZoomable.connectToComboBox(self.mZoomComboBox)
        horizontal.addWidget(self.mZoomComboBox)
        self.mViewStack.currentChanged.connect(self.updateCurrentTiles)
        TilesetManager.instance().tilesetChanged.connect(self.tilesetChanged)
        DocumentManager.instance().documentAboutToClose.connect(
            self.documentAboutToClose)
        self.mTilesetMenuButton.setMenu(self.mTilesetMenu)
        self.mTilesetMenu.aboutToShow.connect(self.refreshTilesetMenu)
        self.setWidget(w)
        self.retranslateUi()
        self.setAcceptDrops(True)
        self.updateActions()

    def __del__(self):
        del self.mCurrentTiles

    ##
    # Sets the map for which the tilesets should be displayed.
    ##
    def setMapDocument(self, mapDocument):
        if (self.mMapDocument == mapDocument):
            return
        # Hide while we update the tab bar, to avoid repeated layouting
        if sys.platform != 'darwin':
            self.widget().hide()

        self.setCurrentTiles(None)
        self.setCurrentTile(None)

        if (self.mMapDocument):
            # Remember the last visible tileset for this map
            tilesetName = self.mTabBar.tabText(self.mTabBar.currentIndex())
            self.mCurrentTilesets.insert(self.mMapDocument, tilesetName)

        # Clear previous content
        while (self.mTabBar.count()):
            self.mTabBar.removeTab(0)
        while (self.mViewStack.count()):
            self.mViewStack.removeWidget(self.mViewStack.widget(0))
        #self.mTilesets.clear()
        # Clear all connections to the previous document
        if (self.mMapDocument):
            self.mMapDocument.disconnect()
        self.mMapDocument = mapDocument
        if (self.mMapDocument):
            self.mTilesets = self.mMapDocument.map().tilesets()
            for tileset in self.mTilesets:
                view = TilesetView()
                view.setMapDocument(self.mMapDocument)
                view.setZoomable(self.mZoomable)
                self.mTabBar.addTab(tileset.name())
                self.mViewStack.addWidget(view)

            self.mMapDocument.tilesetAdded.connect(self.tilesetAdded)
            self.mMapDocument.tilesetRemoved.connect(self.tilesetRemoved)
            self.mMapDocument.tilesetMoved.connect(self.tilesetMoved)
            self.mMapDocument.tilesetNameChanged.connect(
                self.tilesetNameChanged)
            self.mMapDocument.tilesetFileNameChanged.connect(
                self.updateActions)
            self.mMapDocument.tilesetChanged.connect(self.tilesetChanged)
            self.mMapDocument.tileAnimationChanged.connect(
                self.tileAnimationChanged)
            cacheName = self.mCurrentTilesets.take(self.mMapDocument)
            for i in range(self.mTabBar.count()):
                if (self.mTabBar.tabText(i) == cacheName):
                    self.mTabBar.setCurrentIndex(i)
                    break

            object = self.mMapDocument.currentObject()
            if object:
                if object.typeId() == Object.TileType:
                    self.setCurrentTile(object)

        self.updateActions()
        if sys.platform != 'darwin':
            self.widget().show()

    ##
    # Synchronizes the selection with the given stamp. Ignored when the stamp is
    # changing because of a selection change in the TilesetDock.
    ##
    def selectTilesInStamp(self, stamp):
        if self.mEmittingStampCaptured:
            return
        processed = QSet()
        selections = QMap()
        for variation in stamp.variations():
            tileLayer = variation.tileLayer()
            for cell in tileLayer:
                tile = cell.tile
                if tile:
                    if (processed.contains(tile)):
                        continue
                    processed.insert(tile)  # avoid spending time on duplicates
                    tileset = tile.tileset()
                    tilesetIndex = self.mTilesets.indexOf(
                        tileset.sharedPointer())
                    if (tilesetIndex != -1):
                        view = self.tilesetViewAt(tilesetIndex)
                        if (not view.model()):  # Lazily set up the model
                            self.setupTilesetModel(view, tileset)
                        model = view.tilesetModel()
                        modelIndex = model.tileIndex(tile)
                        selectionModel = view.selectionModel()

                        _x = QItemSelection()
                        _x.select(modelIndex, modelIndex)
                        selections[selectionModel] = _x

        if (not selections.isEmpty()):
            self.mSynchronizingSelection = True
            # Mark captured tiles as selected
            for i in selections:
                selectionModel = i[0]
                selection = i[1]
                selectionModel.select(selection,
                                      QItemSelectionModel.SelectCurrent)

            # Show/edit properties of all captured tiles
            self.mMapDocument.setSelectedTiles(processed.toList())
            # Update the current tile (useful for animation and collision editors)
            first = selections.first()
            selectionModel = first[0]
            selection = first[1]
            currentIndex = QModelIndex(selection.first().topLeft())
            if (selectionModel.currentIndex() != currentIndex):
                selectionModel.setCurrentIndex(currentIndex,
                                               QItemSelectionModel.NoUpdate)
            else:
                self.currentChanged(currentIndex)
            self.mSynchronizingSelection = False

    def currentTilesetChanged(self):
        view = self.currentTilesetView()
        if view:
            s = view.selectionModel()
            if s:
                self.setCurrentTile(view.tilesetModel().tileAt(
                    s.currentIndex()))

    ##
    # Returns the currently selected tile.
    ##
    def currentTile(self):
        return self.mCurrentTile

    def changeEvent(self, e):
        super().changeEvent(e)
        x = e.type()
        if x == QEvent.LanguageChange:
            self.retranslateUi()
        else:
            pass

    def dragEnterEvent(self, e):
        urls = e.mimeData().urls()
        if (not urls.isEmpty() and not urls.at(0).toLocalFile().isEmpty()):
            e.accept()

    def dropEvent(self, e):
        paths = QStringList()
        for url in e.mimeData().urls():
            localFile = url.toLocalFile()
            if (not localFile.isEmpty()):
                paths.append(localFile)

        if (not paths.isEmpty()):
            self.tilesetsDropped.emit(paths)
            e.accept()

    def selectionChanged(self):
        self.updateActions()
        if not self.mSynchronizingSelection:
            self.updateCurrentTiles()

    def currentChanged(self, index):
        if (not index.isValid()):
            return
        model = index.model()
        self.setCurrentTile(model.tileAt(index))

    def updateActions(self):
        external = False
        hasImageSource = False
        hasSelection = False
        view = None
        index = self.mTabBar.currentIndex()
        if (index > -1):
            view = self.tilesetViewAt(index)
            if (view):
                tileset = self.mTilesets.at(index)
                if (not view.model()):  # Lazily set up the model
                    self.setupTilesetModel(view, tileset)

                self.mViewStack.setCurrentIndex(index)
                external = tileset.isExternal()
                hasImageSource = tileset.imageSource() != ''
                hasSelection = view.selectionModel().hasSelection()

        tilesetIsDisplayed = view != None
        mapIsDisplayed = self.mMapDocument != None
        self.mNewTileset.setEnabled(mapIsDisplayed)
        self.mImportTileset.setEnabled(tilesetIsDisplayed and external)
        self.mExportTileset.setEnabled(tilesetIsDisplayed and not external)
        self.mPropertiesTileset.setEnabled(tilesetIsDisplayed and not external)
        self.mDeleteTileset.setEnabled(tilesetIsDisplayed)
        self.mEditTerrain.setEnabled(tilesetIsDisplayed and not external)
        self.mAddTiles.setEnabled(tilesetIsDisplayed and not hasImageSource
                                  and not external)
        self.mRemoveTiles.setEnabled(tilesetIsDisplayed and not hasImageSource
                                     and hasSelection and not external)

    def updateCurrentTiles(self):
        view = self.currentTilesetView()
        if (not view):
            return
        s = view.selectionModel()
        if (not s):
            return
        indexes = s.selection().indexes()
        if len(indexes) == 0:
            return
        first = indexes[0]
        minX = first.column()
        maxX = first.column()
        minY = first.row()
        maxY = first.row()
        for index in indexes:
            if minX > index.column():
                minX = index.column()
            if maxX < index.column():
                maxX = index.column()
            if minY > index.row():
                minY = index.row()
            if maxY < index.row():
                maxY = index.row()

        # Create a tile layer from the current selection
        tileLayer = TileLayer(QString(), 0, 0, maxX - minX + 1,
                              maxY - minY + 1)
        model = view.tilesetModel()
        for index in indexes:
            tileLayer.setCell(index.column() - minX,
                              index.row() - minY, Cell(model.tileAt(index)))

        self.setCurrentTiles(tileLayer)

    def indexPressed(self, index):
        view = self.currentTilesetView()
        tile = view.tilesetModel().tileAt(index)
        if tile:
            self.mMapDocument.setCurrentObject(tile)

    def tilesetAdded(self, index, tileset):
        view = TilesetView()
        view.setMapDocument(self.mMapDocument)
        view.setZoomable(self.mZoomable)
        self.mTilesets.insert(index, tileset.sharedPointer())
        self.mTabBar.insertTab(index, tileset.name())
        self.mViewStack.insertWidget(index, view)
        self.updateActions()

    def tilesetChanged(self, tileset):
        # Update the affected tileset model, if it exists
        index = indexOf(self.mTilesets, tileset)
        if (index < 0):
            return
        model = self.tilesetViewAt(index).tilesetModel()
        if model:
            model.tilesetChanged()

    def tilesetRemoved(self, tileset):
        # Delete the related tileset view
        index = indexOf(self.mTilesets, tileset)
        self.mTilesets.removeAt(index)
        self.mTabBar.removeTab(index)
        self.tilesetViewAt(index).close()

        # Make sure we don't reference this tileset anymore
        if (self.mCurrentTiles):
            # TODO: Don't clean unnecessarily (but first the concept of
            #       "current brush" would need to be introduced)
            cleaned = self.mCurrentTiles.clone()
            cleaned.removeReferencesToTileset(tileset)
            self.setCurrentTiles(cleaned)

        if (self.mCurrentTile and self.mCurrentTile.tileset() == tileset):
            self.setCurrentTile(None)
        self.updateActions()

    def tilesetMoved(self, _from, to):
        self.mTilesets.insert(to, self.mTilesets.takeAt(_from))
        # Move the related tileset views
        widget = self.mViewStack.widget(_from)
        self.mViewStack.removeWidget(widget)
        self.mViewStack.insertWidget(to, widget)
        self.mViewStack.setCurrentIndex(self.mTabBar.currentIndex())
        # Update the titles of the affected tabs
        start = min(_from, to)
        end = max(_from, to)
        for i in range(start, end + 1):
            tileset = self.mTilesets.at(i)
            if (self.mTabBar.tabText(i) != tileset.name()):
                self.mTabBar.setTabText(i, tileset.name())

    def tilesetNameChanged(self, tileset):
        index = indexOf(self.mTilesets, tileset)
        self.mTabBar.setTabText(index, tileset.name())

    def tileAnimationChanged(self, tile):
        view = self.currentTilesetView()
        if view:
            model = view.tilesetModel()
            if model:
                model.tileChanged(tile)

    ##
    # Removes the currently selected tileset.
    ##
    def removeTileset(self, *args):
        l = len(args)
        if l == 0:
            currentIndex = self.mViewStack.currentIndex()
            if (currentIndex != -1):
                self.removeTileset(self.mViewStack.currentIndex())
        elif l == 1:
            ##
            # Removes the tileset at the given index. Prompting the user when the tileset
            # is in use by the map.
            ##
            index = args[0]
            tileset = self.mTilesets.at(index).data()
            inUse = self.mMapDocument.map().isTilesetUsed(tileset)
            # If the tileset is in use, warn the user and confirm removal
            if (inUse):
                warning = QMessageBox(
                    QMessageBox.Warning, self.tr("Remove Tileset"),
                    self.tr("The tileset \"%s\" is still in use by the map!" %
                            tileset.name()), QMessageBox.Yes | QMessageBox.No,
                    self)
                warning.setDefaultButton(QMessageBox.Yes)
                warning.setInformativeText(
                    self.tr("Remove this tileset and all references "
                            "to the tiles in this tileset?"))
                if (warning.exec() != QMessageBox.Yes):
                    return

            remove = RemoveTileset(self.mMapDocument, index, tileset)
            undoStack = self.mMapDocument.undoStack()
            if (inUse):
                # Remove references to tiles in this tileset from the current map
                def referencesTileset(cell):
                    tile = cell.tile
                    if tile:
                        return tile.tileset() == tileset
                    return False

                undoStack.beginMacro(remove.text())
                removeTileReferences(self.mMapDocument, referencesTileset)

            undoStack.push(remove)
            if (inUse):
                undoStack.endMacro()

    def moveTileset(self, _from, to):
        command = MoveTileset(self.mMapDocument, _from, to)
        self.mMapDocument.undoStack().push(command)

    def editTilesetProperties(self):
        tileset = self.currentTileset()
        if (not tileset):
            return
        self.mMapDocument.setCurrentObject(tileset)
        self.mMapDocument.emitEditCurrentObject()

    def importTileset(self):
        tileset = self.currentTileset()
        if (not tileset):
            return
        command = SetTilesetFileName(self.mMapDocument, tileset, QString())
        self.mMapDocument.undoStack().push(command)

    def exportTileset(self):
        tileset = self.currentTileset()
        if (not tileset):
            return

        tsxFilter = self.tr("Tiled tileset files (*.tsx)")
        helper = FormatHelper(FileFormat.ReadWrite, tsxFilter)

        prefs = preferences.Preferences.instance()

        suggestedFileName = prefs.lastPath(
            preferences.Preferences.ExternalTileset)
        suggestedFileName += '/'
        suggestedFileName += tileset.name()

        extension = ".tsx"

        if (not suggestedFileName.endswith(extension)):
            suggestedFileName += extension

        selectedFilter = tsxFilter
        fileName, _ = QFileDialog.getSaveFileName(self,
                                                  self.tr("Export Tileset"),
                                                  suggestedFileName,
                                                  helper.filter(),
                                                  selectedFilter)
        if fileName == '':
            return
        prefs.setLastPath(preferences.Preferences.ExternalTileset,
                          QFileInfo(fileName).path())

        tsxFormat = TsxTilesetFormat()
        format = helper.formatByNameFilter(selectedFilter)
        if not format:
            format = tsxFormat

        if format.write(tileset, fileName):
            command = SetTilesetFileName(self.mMapDocument, tileset, fileName)
            self.mMapDocument.undoStack().push(command)
        else:
            error = format.errorString()
            QMessageBox.critical(self.window(), self.tr("Export Tileset"),
                                 self.tr("Error saving tileset: %s" % error))

    def editTerrain(self):
        tileset = self.currentTileset()
        if (not tileset):
            return
        editTerrainDialog = EditTerrainDialog(self.mMapDocument, tileset, self)
        editTerrainDialog.exec()

    def addTiles(self):
        tileset = self.currentTileset()
        if (not tileset):
            return
        prefs = preferences.Preferences.instance()
        startLocation = QFileInfo(
            prefs.lastPath(preferences.Preferences.ImageFile)).absolutePath()
        filter = Utils.readableImageFormatsFilter()
        files = QFileDialog.getOpenFileNames(self.window(),
                                             self.tr("Add Tiles"),
                                             startLocation, filter)
        tiles = QList()
        id = tileset.tileCount()
        for file in files:
            image = QPixmap(file)
            if (not image.isNull()):
                tiles.append(Tile(image, file, id, tileset))
                id += 1
            else:
                warning = QMessageBox(QMessageBox.Warning,
                                      self.tr("Add Tiles"),
                                      self.tr("Could not load \"%s\"!" % file),
                                      QMessageBox.Ignore | QMessageBox.Cancel,
                                      self.window())
                warning.setDefaultButton(QMessageBox.Ignore)
                if (warning.exec() != QMessageBox.Ignore):
                    tiles.clear()
                    return

        if (tiles.isEmpty()):
            return
        prefs.setLastPath(preferences.Preferences.ImageFile, files.last())
        self.mMapDocument.undoStack().push(
            AddTiles(self.mMapDocument, tileset, tiles))

    def removeTiles(self):
        view = self.currentTilesetView()
        if (not view):
            return
        if (not view.selectionModel().hasSelection()):
            return
        indexes = view.selectionModel().selectedIndexes()
        model = view.tilesetModel()
        tileIds = RangeSet()
        tiles = QList()
        for index in indexes:
            tile = model.tileAt(index)
            if tile:
                tileIds.insert(tile.id())
                tiles.append(tile)

        def matchesAnyTile(cell):
            tile = cell.tile
            if tile:
                return tiles.contains(tile)
            return False

        inUse = self.hasTileReferences(self.mMapDocument, matchesAnyTile)
        # If the tileset is in use, warn the user and confirm removal
        if (inUse):
            warning = QMessageBox(
                QMessageBox.Warning, self.tr("Remove Tiles"),
                self.tr("One or more of the tiles to be removed are "
                        "still in use by the map!"),
                QMessageBox.Yes | QMessageBox.No, self)
            warning.setDefaultButton(QMessageBox.Yes)
            warning.setInformativeText(
                self.tr("Remove all references to these tiles?"))
            if (warning.exec() != QMessageBox.Yes):
                return

        undoStack = self.mMapDocument.undoStack()
        undoStack.beginMacro(self.tr("Remove Tiles"))
        removeTileReferences(self.mMapDocument, matchesAnyTile)
        # Iterate backwards over the ranges in order to keep the indexes valid
        firstRange = tileIds.begin()
        it = tileIds.end()
        if (it == firstRange):  # no range
            return
        tileset = view.tilesetModel().tileset()
        while (it != firstRange):
            it -= 1
            item = tileIds.item(it)
            length = item[1] - item[0] + 1
            undoStack.push(
                RemoveTiles(self.mMapDocument, tileset, item[0], length))

        undoStack.endMacro()
        # Clear the current tiles, will be referencing the removed tiles
        self.setCurrentTiles(None)
        self.setCurrentTile(None)

    def documentAboutToClose(self, mapDocument):
        self.mCurrentTilesets.remove(mapDocument)

    def refreshTilesetMenu(self):
        self.mTilesetMenu.clear()
        if (self.mTilesetMenuMapper):
            self.mTabBar.disconnect(self.mTilesetMenuMapper)
            del self.mTilesetMenuMapper

        self.mTilesetMenuMapper = QSignalMapper(self)
        self.mTilesetMenuMapper.mapped.connect(self.mTabBar.setCurrentIndex)
        currentIndex = self.mTabBar.currentIndex()
        for i in range(self.mTabBar.count()):
            action = QAction(self.mTabBar.tabText(i), self)
            action.setCheckable(True)
            self.mTilesetActionGroup.addAction(action)
            if (i == currentIndex):
                action.setChecked(True)
            self.mTilesetMenu.addAction(action)
            action.triggered.connect(self.mTilesetMenuMapper.map)
            self.mTilesetMenuMapper.setMapping(action, i)

    def setCurrentTile(self, tile):
        if (self.mCurrentTile == tile):
            return
        self.mCurrentTile = tile
        self.currentTileChanged.emit([tile])
        if (tile):
            self.mMapDocument.setCurrentObject(tile)

    def setCurrentTiles(self, tiles):
        if (self.mCurrentTiles == tiles):
            return
        del self.mCurrentTiles
        self.mCurrentTiles = tiles
        # Set the selected tiles on the map document
        if (tiles):
            selectedTiles = QList()
            for y in range(tiles.height()):
                for x in range(tiles.width()):
                    cell = tiles.cellAt(x, y)
                    if (not cell.isEmpty()):
                        selectedTiles.append(cell.tile)

            self.mMapDocument.setSelectedTiles(selectedTiles)

            # Create a tile stamp with these tiles
            map = self.mMapDocument.map()
            stamp = Map(map.orientation(), tiles.width(), tiles.height(),
                        map.tileWidth(), map.tileHeight())
            stamp.addLayer(tiles.clone())
            stamp.addTilesets(tiles.usedTilesets())

            self.mEmittingStampCaptured = True
            self.stampCaptured.emit(TileStamp(stamp))
            self.mEmittingStampCaptured = False

    def retranslateUi(self):
        self.setWindowTitle(self.tr("Tilesets"))
        self.mNewTileset.setText(self.tr("New Tileset"))
        self.mImportTileset.setText(self.tr("Import Tileset"))
        self.mExportTileset.setText(self.tr("Export Tileset As..."))
        self.mPropertiesTileset.setText(self.tr("Tileset Properties"))
        self.mDeleteTileset.setText(self.tr("Remove Tileset"))
        self.mEditTerrain.setText(self.tr("Edit Terrain Information"))
        self.mAddTiles.setText(self.tr("Add Tiles"))
        self.mRemoveTiles.setText(self.tr("Remove Tiles"))

    def currentTileset(self):
        index = self.mTabBar.currentIndex()
        if (index == -1):
            return None
        return self.mTilesets.at(index)

    def currentTilesetView(self):
        return self.mViewStack.currentWidget()

    def tilesetViewAt(self, index):
        return self.mViewStack.widget(index)

    def setupTilesetModel(self, view, tileset):
        view.setModel(TilesetModel(tileset, view))

        s = view.selectionModel()
        s.selectionChanged.connect(self.selectionChanged)
        s.currentChanged.connect(self.currentChanged)
        view.pressed.connect(self.indexPressed)
class BooleanWidget(QWidget, NinjaWidget):
    def __init__(self, entity_data, parent=None):
        self._boolean_data = entity_data
        widget_name = self._parse_widget_name(
            self._boolean_data[EntityNameMorphology.ENTITY_NAME.value])
        QWidget.__init__(self, widget_name=widget_name)
        NinjaWidget.__init__(self, widget_name=widget_name)

        self._boolean_behaviour = {}
        self._booleans_stacked_widget = None
        self._status_message_from_communication = {}
        self._current_is_on = None
        self._frame = None

        self._parse_status_behaviour()
        self._build_ui()
        self._set_style()
        self._init_connections()

    def _init_connections(self):
        communication_instance.signal_status_update.connect(
            self._slot_incoming_status)

    def _set_style(self):
        self.setMaximumWidth(_Parameters.TOTAL_WIDGET_WIDTH.value)
        self.setMaximumHeight(_Parameters.TOTAL_WIDGET_HEIGHT.value)
        # self._frame.setParent(self)
        # self._frame.setStyleSheet('border: 1px solid black;')

    def _parse_status_behaviour(self):
        status_behaviour_str = {}
        with open(self._boolean_data[EntityNameMorphology.ENTITY_FOLDER.value],
                  'r') as file:
            status_behaviour_str = file.read()
        try:
            self._boolean_behaviour = eval(status_behaviour_str)
        except Exception as e:
            self._log('eval failed with: {}'.format(status_behaviour_str))

    def _build_ui(self):
        # self._frame = QFrame()
        # horizontal_layout = QHBoxLayout(self._frame)
        horizontal_layout = QHBoxLayout(self)
        self.setLayout(horizontal_layout)

        self._booleans_stacked_widget = QStackedWidget()
        self._init_booleans_types()

        header_label = QLabel()
        header_label.setText(
            self._boolean_behaviour[StatusBehaviourKey.LABEL_TEXT.value])
        header_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        # header_label.setMaximumWidth(_Parameters.HEADER_LABEL_WIDTH.value)
        # header_label.setMaximumHeight(_Parameters.HEADER_LABEL_HEIGHT.value)

        self._set_boolean_type()

        # Order is important
        horizontal_layout.addWidget(header_label)
        horizontal_layout.addWidget(self._booleans_stacked_widget)

    def _init_booleans_types(self):
        self._init_boolean_type(_BooleanType.NONE.value,
                                _Parameters.NONE_ICON_NAME.value)
        self._init_boolean_type(_BooleanType.ON.value,
                                _Parameters.TRUE_ICON_NAME.value)
        self._init_boolean_type(_BooleanType.OFF.value,
                                _Parameters.FALSE_ICON_NAME.value)

    def _init_boolean_type(self, index, resource_name):
        boolean_label = QLabel()
        boolean_label.setMaximumWidth(_Parameters.BOOLEAN_BULB_WIDTH.value)
        # boolean_label.setMinimumWidth(20)
        boolean_label.setMaximumHeight(_Parameters.BOOLEAN_BULB_HEIGHT.value)
        # boolean_label.setMinimumHeight(20)
        boolean_path = os.path.join(General.RESOURCES_FOLDER.value,
                                    resource_name)
        boolean_pixmap = QPixmap(boolean_path)
        boolean_pixmap.scaled(boolean_label.size(), Qt.KeepAspectRatio)
        boolean_label.setPixmap(boolean_pixmap)
        boolean_label.setScaledContents(True)

        self._booleans_stacked_widget.insertWidget(index, boolean_label)

    def _set_boolean_type(self):
        index = 0
        if self._current_is_on is None:
            index = _BooleanType.NONE.value
        elif self._current_is_on:
            index = _BooleanType.ON.value
        else:
            index = _BooleanType.OFF.value

        self._booleans_stacked_widget.setCurrentIndex(index)

    @pyqtSlot('QString')
    def _slot_incoming_status(self, message):
        received_json = json.loads(message)
        self._status_message_from_communication = received_json

        try:
            required_status = self._boolean_behaviour[
                StatusBehaviourKey.STATUS_FROM_COMMUNICATION.value]
            if self._status_message_from_communication[
                    'status'] == required_status:
                first_key = self._boolean_behaviour[
                    StatusBehaviourKey.PATH_IN_MESSAGE.value][0]
                compliment_keys = self._boolean_behaviour[
                    StatusBehaviourKey.PATH_IN_MESSAGE.value][1:]

                # Extract keys
                status = self._status_message_from_communication[first_key]
                for key in compliment_keys:
                    status = status[key]

                self._current_is_on = bool(status)
                self._set_boolean_type()
        except Exception as e:
            self._log(
                'Path in message  wasn\'t correct is {}, Error was {}'.format(
                    self._boolean_data[
                        EntityNameMorphology.ENTITY_FOLDER.value], str(e)))
Beispiel #12
0
class Main(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.stacked_widget.currentChanged.connect(self.set_button_state)
        self.next_button.clicked.connect(self.next_page)
        self.setGeometry(300, 300, 750, 800)
        self.mouse_clik_counter = 0
        self.player = Client()
        self.currentPlayer = None
        self.thread = ServerListener(self.player.client)
        self.thread.route.connect(self.routeGame)

    def closeEvent(self, event):
        if self.player.playerID:
            self.player.disconnect()

    def initUI(self):

        self.next_button = QPushButton('Dalej')
        self.next_button.setEnabled(False)
        self.stacked_widget = QStackedWidget()

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.next_button)

        vbox = QVBoxLayout()
        vbox.addWidget(self.stacked_widget)
        vbox.addLayout(hbox)

        self.setLayout(vbox)

    def set_button_state(self, index):
        n_pages = len(self.stacked_widget)
        self.next_button.setEnabled(index % n_pages < n_pages - 1)

    def insert_page(self, widget, index=-1):
        self.stacked_widget.insertWidget(index, widget)
        self.set_button_state(self.stacked_widget.currentIndex())

    def next_page(self):
        new_index = self.stacked_widget.currentIndex() + 1
        if new_index < len(self.stacked_widget):
            self.stacked_widget.setCurrentIndex(new_index)

        if self.mouse_clik_counter == 0:
            self.next_button.setText("Graj!")
            self.mouse_clik_counter += 1
            self.player.register(self.player_name_input.text())
            self.refreshList()

        elif self.mouse_clik_counter == 1:
            pass

    def welcomeTabUI(self):
        """Create the Welcome page UI."""
        self.grid = QFormLayout()
        self.grid.setFormAlignment(Qt.AlignCenter | Qt.AlignCenter
                                   | Qt.AlignCenter)

        self.player_name_input = QLineEdit('Player')

        self.player_name_label = QLabel("Podaj swoją nazwę gracza", self)
        self.title_label = QLabel("Witaj w Connect4", self)
        self.title_label.setStyleSheet("font: 30pt Century Gothic")
        self.player_name_label.setStyleSheet("font: 15pt Century Gothic")
        self.title_label.setAlignment(Qt.AlignLeading | Qt.AlignCenter
                                      | Qt.AlignCenter)
        self.player_name_label.setAlignment(Qt.AlignCenter | Qt.AlignCenter
                                            | Qt.AlignCenter)
        self.player_name_input.setAlignment(Qt.AlignCenter | Qt.AlignCenter
                                            | Qt.AlignCenter)
        self.grid.addWidget(self.title_label)
        self.grid.addWidget(self.player_name_label)
        self.grid.addWidget(self.player_name_input)

        generalTab = QWidget()
        generalTab.setLayout(self.grid)

        return generalTab

    def gameTabUI(self):
        """Create the Game page UI."""
        generalTab = QWidget()
        self.resultTable = ResulTable()
        self.game = Game()
        layout = QHBoxLayout()
        layout.addWidget(self.game)
        layout.addWidget(self.resultTable)
        generalTab.setLayout(layout)
        return generalTab

    def networkTabUI(self):
        """init boxes"""
        self.networkTab = QWidget()
        self.layout_main = QVBoxLayout()
        self.layout_create_room = QHBoxLayout()
        """Create room layout"""
        self.room_name_input = QLineEdit(self)
        self.room_name_label = QLabel("Nazwa", self)
        self.layout_create_room.addWidget(self.room_name_label)
        self.layout_create_room.addWidget(self.room_name_input)
        """Main layout"""
        self.list = QListWidget()
        self.list.currentItemChanged.connect(self.selected_room)
        self.btn_add_room = QPushButton('Dodaj pokój')
        self.btn_add_room.clicked.connect(self.create_room)
        self.btn_get_rooms = QPushButton('Odśwież listę pokoi')
        self.btn_get_rooms.clicked.connect(self.refreshList)
        self.selected_room_input = QLineEdit()
        self.btn_enter_room = QPushButton('Wejdź do pokoju')
        self.btn_enter_room.clicked.connect(self.enterToRoom)
        self.info_label = QLabel()
        self.info_label.setStyleSheet("font: 15pt Century Gothic; color: red")
        self.layout_main.addWidget(QLabel("Stwórz nowy pokój", self))
        self.layout_main.addLayout(self.layout_create_room)
        self.layout_main.addWidget(self.btn_add_room)
        self.layout_main.addWidget(self.btn_get_rooms)
        self.layout_main.addWidget(QHLine())
        self.layout_main.addWidget(QLabel("Wybierz pokój", self))
        self.layout_main.addWidget(self.list)
        self.layout_main.addWidget(self.selected_room_input)
        self.layout_main.addWidget(self.btn_enter_room)
        self.layout_main.addWidget(self.info_label)
        self.networkTab.setLayout(self.layout_main)

        return self.networkTab

    def refreshList(self):
        self.rooms = self.player.getRoomList()
        self.rooms.sort(key=lambda x: x[0])
        self.list.clear()
        for room in self.rooms:
            self.list.addItem(
                f"{room[0]} The current number of players {room[2]}")

    def selected_room(self):
        selectedRoom = self.rooms[self.list.currentRow()]
        self.selected_room_input.setText(selectedRoom[0])

    def create_room(self):
        if self.room_name_input.text():
            self.player.createRoom(self.room_name_input.text())
            self.refreshList()
            self.thread.start()
            self.info_label.setText(
                f"Stworzono pokój: {self.room_name_input.text()}. Poczekaj na drugiego gracza."
            )
            self.btn_add_room.setDisabled(True)
            self.btn_enter_room.setDisabled(True)
            self.btn_get_rooms.setDisabled(True)
        else:
            self.info_label.setText("Wpisz nazwę pokoju")

    def enterToRoom(self):
        if len(self.selected_room_input.text()) > 0:
            for room in self.rooms:
                if room[0] == self.selected_room_input.text():
                    if self.player.joinToRoom(room[1]):
                        self.routeGame({'action': 'startGame'})
                    else:
                        self.info_label.setText("Nie można wejść do pokoju")
                    break
            else:
                self.info_label.setText("Nie znaleziono pokoju")
        else:
            self.info_label.setText("Nie wybrano pokoju")

    def routeGame(self, data):

        action = data['action']

        if action == 'startGame':
            self.currentPlayer = self.player.getCurrentPlayer()
            if self.currentPlayer[1] != self.player.playerID:
                self.thread.start()
            self.game.currentPlayer = self.currentPlayer
            self.game.player = self.player
            self.game.thread = self.thread
            self.game.resultTable = self.resultTable
            self.resultTable.setCurrentPlayer(self.currentPlayer[0])
            self.next_page()

        elif action == 'changePlayer':
            self.currentPlayer = self.player.getCurrentPlayer()
            self.resultTable.setCurrentPlayer(self.currentPlayer[0])
            self.game.currentPlayer = self.currentPlayer
            self.resultTable.setCurrentPlayer(self.currentPlayer[0])
Beispiel #13
0
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.initUI()
        self.stacked_widget.currentChanged.connect(self.set_button_state)
        self.next_button.clicked.connect(self.next_page)
        self.prev_button.clicked.connect(self.prev_page)


    def initUI(self):
        self.next_button = QPushButton('Next')
        self.prev_button = QPushButton('Previous')
        self.next_button.setEnabled(False)
        self.prev_button.setEnabled(False)
        self.stacked_widget = QStackedWidget()
        
        widget = QtWidgets.QWidget()
        self.setCentralWidget(widget)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.prev_button)
        hbox.addWidget(self.next_button)

        vbox = QVBoxLayout()
        vbox.addWidget(self.stacked_widget)
        vbox.addLayout(hbox)
        
        h = HomeScreen(self)
        self.insert_page(h.label1)
        
        navigation = Navigation(sample, self)
        self.insert_page(navigation.horizontalGroupBox)

        #add the toolbar to the main window
        self.toolbar = navigation.toolbar
        self.addToolBar(self.toolbar)
        
        #start with the toolbar hidden
        self.toolbar.toggleViewAction().setChecked(True)
        self.toolbar.toggleViewAction().trigger()
        
        # create main layout
        widget.setLayout(vbox)


    def set_button_state(self, index):
        self.prev_button.setEnabled(index > 0)
        n_pages = len(self.stacked_widget)
        self.next_button.setEnabled( index % n_pages < n_pages - 1)
        
        
    def insert_page(self, widget, index=-1):
        self.stacked_widget.insertWidget(index, widget)
        self.set_button_state(self.stacked_widget.currentIndex())
        

    def next_page(self):
        new_index = self.stacked_widget.currentIndex()+1
        if new_index < len(self.stacked_widget):
            self.stacked_widget.setCurrentIndex(new_index)
            self.toolbar.toggleViewAction().trigger()
            

    def prev_page(self):
        new_index = self.stacked_widget.currentIndex()-1
        if new_index >= 0:
            self.stacked_widget.setCurrentIndex(new_index)
            self.toolbar.toggleViewAction().trigger()
Beispiel #14
0
class SubTabWidget(QWidget):
    _tabChanged = pyqtSignal(int, name = "tabChanged")

    def __init__(self, subtitleData, videoWidget, parent = None):
        super(SubTabWidget, self).__init__(parent)
        self._subtitleData = subtitleData
        self.__initTabWidget(videoWidget)

    def __initTabWidget(self, videoWidget):
        settings = SubSettings()

        mainLayout = QVBoxLayout(self)
        mainLayout.setContentsMargins(0, 0, 0, 0)
        mainLayout.setSpacing(0)

        #TabBar
        self.tabBar = QTabBar(self)

        # Splitter (bookmarks + pages)
        self.splitter = QSplitter(self)
        self.splitter.setObjectName("sidebar_splitter")

        self._toolbox = ToolBox(self._subtitleData, self)
        self._toolbox.setObjectName("sidebar")
        self._toolbox.setMinimumWidth(100)

        self._toolbox.addTool(Details(self._subtitleData, self))
        self._toolbox.addTool(Synchronizer(videoWidget, self._subtitleData, self))
        self._toolbox.addTool(History(self))

        self.rightWidget = QWidget()
        rightLayout = QGridLayout()
        rightLayout.setContentsMargins(0, 0, 0, 0)
        self.rightWidget.setLayout(rightLayout)

        self._mainTab = FileList(_("Subtitles"), self._subtitleData, self)

        self.pages = QStackedWidget(self)
        rightLayout.addWidget(self.pages, 0, 0)

        self.tabBar.addTab(self._mainTab.name)
        self.pages.addWidget(self._mainTab)

        self.splitter.addWidget(self._toolbox)
        self.splitter.addWidget(self.rightWidget)
        self.__drawSplitterHandle(1)

        # Setting widgets
        mainLayout.addWidget(self.tabBar)
        mainLayout.addWidget(self.splitter)

        # Widgets settings
        self.tabBar.setMovable(True)
        self.tabBar.setTabsClosable(True)
        self.tabBar.setExpanding(False)

        # Don't resize left panel if it's not needed
        leftWidgetIndex = self.splitter.indexOf(self._toolbox)
        rightWidgetIndex = self.splitter.indexOf(self.rightWidget)

        self.splitter.setStretchFactor(leftWidgetIndex, 0)
        self.splitter.setStretchFactor(rightWidgetIndex, 1)
        self.splitter.setCollapsible(leftWidgetIndex, False)
        self.splitter.setSizes([250])

        # Some signals
        self.tabBar.currentChanged.connect(self.showTab)
        self.tabBar.tabCloseRequested.connect(self.closeTab)
        self.tabBar.tabMoved.connect(self.moveTab)
        self._mainTab.requestOpen.connect(self.openTab)
        self._mainTab.requestRemove.connect(self.removeFile)

        self.tabChanged.connect(lambda i: self._toolbox.setContentFor(self.tab(i)))

        self.setLayout(mainLayout)

    def __addTab(self, filePath):
        """Returns existing tab index. Creates a new one if it isn't opened and returns its index
        otherwise."""
        for i in range(self.tabBar.count()):
            widget = self.pages.widget(i)
            if not widget.isStatic and filePath == widget.filePath:
                return i
        tab = SubtitleEditor(filePath, self._subtitleData, self)
        newIndex = self.tabBar.addTab(self._createTabName(tab.name, tab.history.isClean()))
        tab.history.cleanChanged.connect(
            lambda clean: self._cleanStateForFileChanged(filePath, clean))
        self.pages.addWidget(tab)
        return newIndex

    def __drawSplitterHandle(self, index):
        splitterHandle = self.splitter.handle(index)

        splitterLayout = QVBoxLayout(splitterHandle)
        splitterLayout.setSpacing(0)
        splitterLayout.setContentsMargins(0, 0, 0, 0)

        line = QFrame(splitterHandle)
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        splitterLayout.addWidget(line)
        splitterHandle.setLayout(splitterLayout)

    def _createTabName(self, name, cleanState):
        if cleanState is True:
            return name
        else:
            return "%s +" % name

    def _cleanStateForFileChanged(self, filePath, cleanState):
        page = self.tabByPath(filePath)
        if page is not None:
            for i in range(self.tabBar.count()):
                if self.tabBar.tabText(i)[:len(page.name)] == page.name:
                    self.tabBar.setTabText(i, self._createTabName(page.name, cleanState))
                    return

    def saveWidgetState(self, settings):
        settings.setState(self.splitter, self.splitter.saveState())
        settings.setHidden(self._toolbox, self._toolbox.isHidden())

    def restoreWidgetState(self, settings):
        self.showPanel(not settings.getHidden(self._toolbox))

        splitterState = settings.getState(self.splitter)
        if not splitterState.isEmpty():
            self.splitter.restoreState(settings.getState(self.splitter))

    @pyqtSlot(str, bool)
    def openTab(self, filePath, background=False):
        if self._subtitleData.fileExists(filePath):
            tabIndex = self.__addTab(filePath)
            if background is False:
                self.showTab(tabIndex)
        else:
            log.error(_("SubtitleEditor not created for %s!" % filePath))

    @pyqtSlot(str)
    def removeFile(self, filePath):
        tab = self.tabByPath(filePath)
        command = RemoveFile(filePath)
        if tab is not None:
            index = self.pages.indexOf(tab)
            if self.closeTab(index):
                self._subtitleData.execute(command)
        else:
            self._subtitleData.execute(command)


    @pyqtSlot(int)
    def closeTab(self, index):
        tab = self.tab(index)
        if tab.canClose():
            widgetToRemove = self.pages.widget(index)
            self.tabBar.removeTab(index)
            self.pages.removeWidget(widgetToRemove)
            widgetToRemove.deleteLater()
            return True
        return False


    def count(self):
        return self.tabBar.count()

    def currentIndex(self):
        return self.tabBar.currentIndex()

    def currentPage(self):
        return self.pages.currentWidget()

    @pyqtSlot(int, int)
    def moveTab(self, fromIndex, toIndex):
        fromWidget = self.pages.widget(fromIndex)
        toWidget = self.pages.widget(toIndex)
        if fromWidget.isStatic or toWidget.isStatic:
            self.tabBar.blockSignals(True) # signals would cause infinite recursion
            self.tabBar.moveTab(toIndex, fromIndex)
            self.tabBar.blockSignals(False)
            return
        else:
            self.pages.removeWidget(fromWidget)
            self.pages.removeWidget(toWidget)

            if fromIndex < toIndex:
                self.pages.insertWidget(fromIndex, toWidget)
                self.pages.insertWidget(toIndex, fromWidget)
            else:
                self.pages.insertWidget(toIndex, fromWidget)
                self.pages.insertWidget(fromIndex, toWidget)

            # Hack
            # Qt changes tabs during mouse drag and dropping. The next line is added
            # to prevent it.
            self.showTab(self.tabBar.currentIndex())

    @pyqtSlot(int)
    def showTab(self, index):
        showWidget = self.pages.widget(index)
        if showWidget:
            self.pages.setCurrentWidget(showWidget)
            self.tabBar.blockSignals(True)
            self.tabBar.setCurrentIndex(index)
            self.tabBar.blockSignals(False)

            # Try to update current tab.
            showWidget.updateTab()

            self._tabChanged.emit(index)

    def showPanel(self, val):
        if val is True:
            self._toolbox.show()
        else:
            self._toolbox.hide()

    def togglePanel(self):
        if self._toolbox.isHidden():
            self._toolbox.show()
        else:
            self._toolbox.hide()

    def tab(self, index):
        return self.pages.widget(index)

    def tabByPath(self, path):
        for i in range(self.pages.count()):
            page = self.tab(i)
            if not page.isStatic and page.filePath == path:
                return page
        return None

    @property
    def fileList(self):
        return self._mainTab
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.label3 = QtWidgets.QLabel()
        self.label3.setGeometry(QtCore.QRect(10, 210, 500, 23))
        self.label3.setObjectName("label3")

        self.btn_Action = QtWidgets.QPushButton()
        self.btn_Action.setGeometry(QtCore.QRect(220, 200, 75, 23))
        self.btn_Action.setObjectName("btn_Action")

        self.gridLayout3 = QtWidgets.QGridLayout()
        self.gridLayout3.addWidget(self.label3, 0, 3, 7, 8)
        self.gridLayout3.addWidget(self.btn_Action, 0, 3, 3, 3)

        self.btn_Action.setText("View Chart")
        self.label3.setText('File Uploaded, check console for its contents')

        self.stacked_widget = QStackedWidget()
        self.stacked_widget.currentChanged.connect(self.set_button_state)
        self.btn_Action.clicked.connect(self.next_page)

        widget = QtWidgets.QWidget()
        self.setCentralWidget(widget)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.btn_Action)

        vbox = QVBoxLayout()
        vbox.addWidget(self.stacked_widget)
        vbox.addLayout(hbox)

        #add the to the main window
        self.toolbar = QToolBar("Edit", self)

        h = HomeScreen(self)
        h.pushButton.clicked.connect(self.file_open)
        self.insert_page(h.centralwidget)

        self.addToolBar(self.toolbar)

        #start with the toolbar hidden
        self.toolbar.toggleViewAction().setChecked(True)
        self.toolbar.toggleViewAction().trigger()

        # create main layout
        widget.setLayout(vbox)

    def file_open(self):
        name, _ = QtWidgets.QFileDialog.getOpenFileName(
            None,
            'Open File',
            options=QtWidgets.QFileDialog.DontUseNativeDialog)
        classObj = FileOpen.openFile(name)
        #print(classObj)
        #chart = Chart('pie1', classObj, self)
        #self.insert_page(chart.chartview)

        navigation = Navigation(classObj, self)
        #self.addToolBar(navigation.toolbar)

        self.insert_page(navigation.horizontalGroupBox)
        #chart = Chart('pie1', classObj, self)
        '''name, _ = QtWidgets.QFileDialog.getOpenFileName(None, 'Open File', options=QtWidgets.QFileDialog.DontUseNativeDialog)
        file = open(name, 'r') 
        with file as json_file:
            text = json.load(json_file)
            #self.label3.setText('File Uploaded, check console for its contents')
            #chart = Chart('Alloys', text, self)
            #self.insert_page(chart.chartview)
       
            navigation = Navigation(text, self)
            self.addToolBar(navigation.toolbar)
           
            self.insert_page(navigation.horizontalGroupBox)'''

    def set_button_state(self, index):
        #self.prev_button.setEnabled(index > 0)
        n_pages = len(self.stacked_widget)
        self.btn_Action.setEnabled(index % n_pages < n_pages - 1)

    def insert_page(self, widget, index=-1):
        self.stacked_widget.insertWidget(index, widget)
        self.set_button_state(self.stacked_widget.currentIndex())

    def next_page(self):
        new_index = self.stacked_widget.currentIndex() + 1
        if new_index < len(self.stacked_widget):
            self.stacked_widget.setCurrentIndex(new_index)
            self.toolbar.toggleViewAction().trigger()
Beispiel #16
0
class TabBarWindow(TabWindow):
    """Implementation which uses a separate QTabBar and QStackedWidget.
    The Tab bar is placed next to the menu bar to save real estate."""
    def __init__(self, app, **kwargs):
        super().__init__(app, **kwargs)

    def _setupUi(self):
        self.setWindowTitle(self.app.NAME)
        self.resize(640, 480)
        self.tabBar = QTabBar()
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self._setupActions()
        self._setupMenu()

        self.centralWidget = QWidget(self)
        self.setCentralWidget(self.centralWidget)
        self.stackedWidget = QStackedWidget()
        self.centralWidget.setLayout(self.verticalLayout)
        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.addWidget(self.menubar, 0, Qt.AlignTop)
        self.horizontalLayout.addWidget(self.tabBar, 0, Qt.AlignTop)
        self.verticalLayout.addLayout(self.horizontalLayout)
        self.verticalLayout.addWidget(self.stackedWidget)

        self.tabBar.currentChanged.connect(self.showWidget)
        self.tabBar.tabCloseRequested.connect(self.onTabCloseRequested)

        self.stackedWidget.currentChanged.connect(self.updateMenuBar)
        self.stackedWidget.widgetRemoved.connect(self.onRemovedWidget)

        self.tabBar.setTabsClosable(True)
        self.restoreGeometry()

    def addTab(self, page, title, switch=True):
        stack_index = self.stackedWidget.insertWidget(-1, page)
        tab_index = self.tabBar.addTab(title)

        if isinstance(page, DirectoriesDialog):
            self.tabBar.setTabButton(tab_index, QTabBar.RightSide, None)
        if switch:  # switch to the added tab immediately upon creation
            self.setTabIndex(tab_index)
            self.stackedWidget.setCurrentWidget(page)
        return stack_index

    @pyqtSlot(int)
    def showWidget(self, index):
        if index >= 0 and index <= self.stackedWidget.count() - 1:
            self.stackedWidget.setCurrentIndex(index)
            # if not self.tabBar.isTabVisible(index):
            self.setTabVisible(index, True)

    def indexOfWidget(self, widget):
        # Warning: this may return -1 if widget is not a child of stackedwidget
        return self.stackedWidget.indexOf(widget)

    def setCurrentIndex(self, tab_index):
        # The signal will handle switching the stackwidget's widget
        self.setTabIndex(tab_index)
        # self.stackedWidget.setCurrentWidget(self.stackedWidget.widget(tab_index))

    @pyqtSlot(int)
    def setTabIndex(self, index):
        if index is None:
            return
        self.tabBar.setCurrentIndex(index)

    def setTabVisible(self, index, value):
        return self.tabBar.setTabVisible(index, value)

    @pyqtSlot(int)
    def onRemovedWidget(self, index):
        self.removeTab(index)

    @pyqtSlot(int)
    def removeTab(self, index):
        # No need to remove the widget here:
        # self.stackedWidget.removeWidget(self.stackedWidget.widget(index))
        return self.tabBar.removeTab(index)

    @pyqtSlot(int)
    def removeWidget(self, widget):
        return self.stackedWidget.removeWidget(widget)

    def isTabVisible(self, index):
        return self.tabBar.isTabVisible(index)

    def getCurrentIndex(self):
        return self.stackedWidget.currentIndex()

    def getWidgetAtIndex(self, index):
        return self.stackedWidget.widget(index)

    def getCount(self):
        return self.stackedWidget.count()

    @pyqtSlot()
    def toggleTabBar(self):
        value = self.sender().isChecked()
        self.actionToggleTabs.setChecked(value)
        self.tabBar.setVisible(value)

    @pyqtSlot(int)
    def onTabCloseRequested(self, index):
        current_widget = self.getWidgetAtIndex(index)
        if isinstance(current_widget, DirectoriesDialog):
            # On MacOS, the tab has a close button even though we explicitely
            # set it to None in order to hide it. This should prevent
            # the "Directories" tab from closing by mistake.
            return
        current_widget.close()
        self.stackedWidget.removeWidget(current_widget)
Beispiel #17
0
class MainWindow(QWidget, app_ui):

    global_vars = {}

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        QWidget.__init__(self)
        self.setupUi(self)

        self.def_setup = MainWindowSettings(self)
        self.def_setup.init_setup()
        self.def_setup.small_size()

        self.ClearSessionAction = QAction("Clear session",
                                          self,
                                          shortcut="Ctrl+W",
                                          triggered=self.reset_input)
        self.input.addAction(self.ClearSessionAction)

        self.stackedWidget = QStackedWidget()
        self.main_grid_layout.addWidget(self.stackedWidget)

        self.setWindowIcon(QIcon(base_dir + "icons/logo.png"))

        self.exts = {}
        self.count = 0

        self.set_plugins()  # search and get all plugins information
        # self.set_plugins_widgets() # for set all plugins
        self.input.textChanged.connect(self.set_plugin)
        self.input.textChanged.connect(self.search_plugin)
        # self.input.returnPressed.connect(self.command_manager)

        self.createActions()
        self.createTrayIcon()
        self.trayIcon.show()

        self.set_input_focus()

    def set_plugins(self):
        for d in glob(base_dir + "exts/*.ext/package.json"):
            script = self.get_json_value(d, "script", "main.py")
            path = os.path.dirname(d) + "/" + script
            kw = str(self.get_json_value(d, "key_word")).strip()

            if (kw and script and path):
                self.exts.update({
                    kw: (self.count, _pkg.Import(path).Plugin,
                         os.path.dirname(d) + "/")
                })
                self.count += 1

    def get_json_value(self, _file: str, key: str, value: str = ""):
        return json.load(open(str(_file))).get(key.lower(), value)

    def set_plugin(self, text: str):
        kw = text.rstrip(":").strip()
        is_ext = text.endswith(":")

        if is_ext and kw in ("end", "clear", "cls"):
            self.def_setup.small_size()
            self.reset_input()
            self.input.addAction(self.ClearSessionAction)

        elif is_ext and kw in ("exit", "quit"):
            self.close()
            self.input.clear()

        elif is_ext and kw in ("update", "reload"):
            self.set_plugins()
            self.input.clear()

        elif is_ext and kw in list(self.exts.keys()):
            self.run_plugin(kw)

    def reset_input(self):
        ## delete last input
        self.gridLayout_2.removeWidget(self.input)
        self.input.deleteLater()

        ## get new input line without any event
        self.set_new_line()

        ## default setup for line input
        self.def_setup.remove_session()
        self.set_input_focus()

    def set_new_line(self):
        ## create line edit by object name input
        self.input = QLineEdit(self)
        self.input.setObjectName("input")

        ## add line to layout
        self.gridLayout_2.addWidget(self.input, 0, 1, 1, 1)

        ## set default setup for line
        self.def_setup.input_setup()

        ## connects functions
        # self.input.returnPressed.connect(self.command_manager)
        self.input.textChanged.connect(self.search_plugin)
        self.input.textChanged.connect(self.set_plugin)

    def set_plugins_widgets(self):
        for _, v in self.exts.items():
            self.stackedWidget.addWidget(v[1](self.input))

    def set_widget_by_name(self, name: str = ""):
        self.stackedWidget.setCurrentIndex(self.exts[name][0])

    def get_ext_value(self, ext: str, key: str = "", value: str = ""):
        root_path = self.exts[ext][2]
        return self.get_json_value(root_path + "package.json", key,
                                   value), root_path

    def search_plugin(self, text: str):
        kw = text.rstrip(":").strip()
        is_ext = text.endswith(":")

        if is_ext and kw in list(self.exts.keys()):
            self.run_plugin(kw)

    def run_plugin(self, key_word: str):
        path = self.exts[key_word][2]
        icon = QIcon(path + self.get_ext_value(key_word, "icon")[0])

        self.input.clear()
        self.input.setPlaceholderText(f"Session: {key_word}")

        self.btn_ext.setText(key_word)
        self.btn_ext.setIcon(icon)

        control = Controls(self)
        self.stackedWidget.insertWidget(
            0, self.exts[key_word][1](self.input, _pkg, control))
        self.stackedWidget.setCurrentIndex(self.exts[key_word][0])

        self.def_setup.larg_size()
        self.set_input_focus()

    def createActions(self):
        self.hideAction = QAction("H&ide/S&how",
                                  self,
                                  shortcut="Alt+Space",
                                  triggered=self.check_win)
        self.quitAction = QAction(_pkg.get_sys_icon("application-exit"),
                                  "&Quit",
                                  self,
                                  triggered=QApplication.instance().quit)
        # self.showAction = QAction("S&how", self, shortcut="Alt+K", triggered=self.check_win)

    def check_win(self):
        if self.isHidden():
            self.show()
        else:
            self.hide()

    def set_input_focus(self):
        self.input_frame.setFocus()
        self.input.setFocus()

    def createTrayIcon(self):
        self.trayIconMenu = QMenu(self)

        self.trayIconMenu.addAction(self.hideAction)
        self.trayIconMenu.addAction(self.quitAction)
        # self.trayIconMenu.addAction(self.showAction)

        self.trayIcon = QSystemTrayIcon(_pkg.icon_path("logo.png", True))
        self.trayIcon.setContextMenu(self.trayIconMenu)

        self.trayIcon.activated.connect(self.check_win)

    def showMessage(self,
                    title: str,
                    body: str,
                    icon: int = 1,
                    limit: int = 5):
        tray = QSystemTrayIcon(_pkg.icon_path("logo.png", True))
        icon_ = tray.MessageIcon(icon)

        tray.showMessage(title, body, icon_, limit * 2000)
        tray.show()
Beispiel #18
0
class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        self.stack = QStackedWidget(self)

        self.user = None

        # Instantiate frames for different pages
        self.main_menu = MenuFrame(self)
        self.game_frame = GameFrame(self)
        self.profile_frame = ProfileFrame(self)
        self.register_frame = RegisterFrame(self)
        self.login_frame = LoginFrame(self)

        # Insert frames into a stack
        self.stack.insertWidget(0, self.main_menu)
        self.stack.insertWidget(1, self.game_frame)
        self.stack.insertWidget(2, self.profile_frame)
        self.stack.insertWidget(3, self.register_frame)
        self.stack.insertWidget(4, self.login_frame)

        # Set current frame to main menu
        self.stack.setCurrentIndex(0)

        # Set window details
        self.setCentralWidget(self.stack)
        self.setWindowTitle("Chess")
        self.setWindowIcon(QIcon('./assets/icons/pawn_icon.png'))
        self.setMinimumSize(1200, 900)
        self.show()

    def closeEvent(self, event):
        if self.user:
            update_user(self.user)  # On close, update user wins/losses/draws
            if self.stack.currentIndex(
            ) == 1 and not self.game_frame.board.saved:
                save_prompt = QMessageBox()
                save_prompt.setWindowIcon(
                    QIcon('./assets/icons/pawn_icon.png'))
                save_prompt.setIcon(QMessageBox.Warning)
                save_prompt.setWindowTitle("Chess")
                save_prompt.setText("Your current progress will be lost.")
                save_prompt.setInformativeText("Do you want to save the game?")
                save_prompt.setStandardButtons(QMessageBox.Save
                                               | QMessageBox.Discard
                                               | QMessageBox.Cancel)
                save_prompt.setDefaultButton(QMessageBox.Save)
                save_prompt.button(QMessageBox.Discard).setText("Don't Save")
                option = save_prompt.exec_()

                # Save
                if option == QMessageBox.Save:
                    self.game_frame.board.save()
                    event.accept()
                # Don't save
                elif option == QMessageBox.Discard:
                    event.accept()
                # Cancel
                else:
                    event.ignore()

    def sign_in(self, user):
        self.user = user
        self.main_menu.name_label.setText(user.username)
        self.main_menu.bottom_left_stack.setCurrentIndex(1)
        self.main_menu.bottom_right_stack.setCurrentIndex(1)

    def sign_out(self):
        self.user = None
        self.main_menu.bottom_left_stack.setCurrentIndex(0)
        self.main_menu.bottom_right_stack.setCurrentIndex(0)
Beispiel #19
0
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.setWindowTitle("")
        self.screens_config = []
        self.current_screen = 0
        self.sub_screens = {}
        self.button = {}
        self.central_widget = QStackedWidget()
        self.number_of_subs = 0
        self.main_layout = QGridLayout()
        self.gui_element_builder = GuiElementsBuilder()

    def say_hello(self):
        print("Button clicked, Hello!")

    def set_central_widget2(self, widget: QWidget):
        source_button = self.sender()
        print("set_central_widget2 WidgetName:  " + widget.getName())
        index = self.central_widget.widget(widget)
        self.central_widget.setCurrentIndex(index)

    def set_central_widget(self):
        source_button = self.sender()
        for i in range(0, self.number_of_subs):
            if self.central_widget.widget(i).getName() == source_button.text():
                self.central_widget.setCurrentIndex(i)

    def change_widget(self, widget: QWidget, direction: int):
        #print("len: " + str(len(self.screens_config["sub"])))
        max_screen = len(self.screens_config["sub"])
        if direction == 0:
            self.central_widget.setCurrentIndex(
                (self.central_widget.currentIndex() - 1) % max_screen)
            #self.current_screen = (self.current_screen + 1) % max_screen
        elif direction == 1:
            self.central_widget.setCurrentIndex(
                (self.central_widget.currentIndex() + 1) % max_screen)
            #self.current_screen = (self.current_screen - 1) % max_screen
        else:
            print("that not a valid direction")

        #Farbe sollte im Widget selbst geetzt werden bzw. schon bei Erstellung
        #for items in self.screens_config['sub']:
        #b = QColor(self.screens_config['sub'][self.current_screen]["Background"])
        #b = QColor(self.screens_config['sub'][self.central_widget.currentIndex()]["Background"])
        #p = self.central_widget.palette()
        #p.setColor(self.central_widget.backgroundRole(), b)
        #self.central_widget.setPalette(p)
        #self.central_widget.setAutoFillBackground(True)

    def init_with_config(self, config: dict):
        self.screens_config = config

        # TODO: put in delegation or inheritance
        #Set Title
        if 'name' not in config:
            title = str(config['main']['name'])
            self.setWindowTitle(title)
            # Set Resolution
            window_width = config['main']["resolution"][0]
            window_height = config['main']["resolution"][1]
            button_width = config['main']["button-size"][0]
            button_height = config['main']["button-size"][1]
            self.number_of_subs = len(config['sub'])
        else:
            title = str(config['name'])
            self.setWindowTitle(title)
            # Set Resolution
            window_width = config["resolution"][0]
            window_height = config["resolution"][1]
            button_width = config["button-size"][0]
            button_height = config["button-size"][1]
            self.number_of_subs = len(self.screens_config["sub"])
        self.setFixedSize(window_width, window_height)

        main_widget = QWidget()
        main_widget.setLayout(self.main_layout)
        vbox_menu = QVBoxLayout()
        vbox_menu.setSizeConstraint(QLayout.SetFixedSize)

        system_color = "#ffd966"

        # Header
        self.main_layout.addWidget(
            self.gui_element_builder.get_svg_widget(Gui_Element.TOP_LEFT, 0,
                                                    0), 0, 0)
        self.main_layout.addWidget(
            self.gui_element_builder.get_svg_widget(Gui_Element.BUTTON, 30,
                                                    650), 0, 1, Qt.AlignTop)
        self.main_layout.addWidget(
            self.gui_element_builder.get_svg_widget(Gui_Element.END_RIGHT, 0,
                                                    0), 0, 3, Qt.AlignTop)

        # Menu
        self.main_layout.addLayout(vbox_menu, 1, 0)

        # Footer
        self.main_layout.addWidget(
            self.gui_element_builder.get_svg_widget(Gui_Element.BOTTOM_LEFT, 0,
                                                    0), 2, 0)
        self.main_layout.addWidget(
            self.gui_element_builder.get_svg_widget(Gui_Element.BUTTON, 30,
                                                    650), 2, 1, Qt.AlignBottom)
        self.main_layout.addWidget(
            self.gui_element_builder.get_svg_widget(Gui_Element.END_RIGHT, 0,
                                                    0), 2, 3, Qt.AlignBottom)

        # button_stylesheet = "background-color:" + system_color +"; border-width: 2px; border-radius: 36px; bordericolor: black; font: bold 14px; min-width: 10em; padding: 6px;"
        # button_up = QPushButton("\u1403")
        # button_up.setFixedSize(button_width * window_width/100, button_height * window_height/100)
        # button_up.setStyleSheet(button_stylesheet)
        #
        # button_down = QPushButton("\u1401")
        # button_down.setFixedSize(button_width * window_width / 100, button_height * window_height / 100)
        # button_down.setStyleSheet(button_stylesheet)

        button_ListWidget = QListWidget()
        button_ListWidget.setStyleSheet(
            """QListWidget{background: #f2eeed;  border: 0px solid #f2eeed;}"""
        )
        # Erstellen der rechten Button-Leiste ##############
        #vbox_menu.addWidget(button_up)
        button_width = button_width * window_width / 100
        button_height = button_height * window_height / 100
        background_color = "#f2eeed"
        button_size = QSize(button_width, button_height)
        for i in range(0, self.number_of_subs):
            subbutton_list_item = QListWidgetItem(button_ListWidget)
            placeholder_listItem = QListWidgetItem(button_ListWidget)
            placeholder_listItem.setSizeHint(QSize(button_width, 4))

            flag = placeholder_listItem.flags() & Qt.ItemIsUserCheckable
            placeholder_listItem.setFlags(flag)
            #subbutton_listItem.setBackground(QColor("#f2eeed"))
            # Widgets ##################################################################################################
            if i == 0:
                self.central_widget.insertWidget(i, Clock())
            else:
                self.central_widget.insertWidget(
                    i, Placeholder(self.screens_config["sub"][i]["name"]))
            # Buttons ##################################################################################################
            button_color = self.screens_config['sub'][i]["Background"]
            self.button[i] = QPushButton(self.screens_config["sub"][i]["name"],
                                         self)
            self.button[i].setFixedSize(button_size)

            #Button with stylsheet
            #self.button[i].setStyleSheet("background-color:" +button_color +"; border-width: 2px; border-radius: 10px; bordericolor: black; font: bold 14px; min-width: 10em; padding: 6px;")

            path_button = Button_full.build_svg(
                Button_full(
                    button_width, button_height, background_color,
                    self.screens_config["sub"][i]["Background"] + "_button"))
            self.button[i].setStyleSheet("background-image: url(" +
                                         path_button + ");"
                                         "border:1px; background-color:" +
                                         button_color + ";")
            #print("Button: " + self.button[i].text() + "Screen: " + self.central_widget.widget(i).getName())
            # signals ##################################################################################################
            #self.button[i].clicked.connect(lambda widget=self.central_widget.widget(i): self.set_central_widget2(self, widget))
            self.button[i].clicked.connect(
                lambda widget=self.central_widget.widget(
                    i): self.set_central_widget())
            subbutton_list_item.setSizeHint(button_size)
            #print(self.button[i].size())
            #
            button_ListWidget.addItem(placeholder_listItem)
            button_ListWidget.addItem(subbutton_list_item)
            button_ListWidget.setItemWidget(subbutton_list_item,
                                            self.button[i])
            button_ListWidget.setMaximumWidth(1000)
            #vbox_menu.addWidget(self.button[i])

        vbox_menu.addWidget(button_ListWidget)
        #vbox_menu.addWidget(button_down)
        #downbutton_listItem = QListWidgetItem(button_ListWidget)
        #downbutton_listItem.setSizeHint(button_down.size())
        #button_ListWidget.addItem(downbutton_listItem)
        #button_ListWidget.setItemWidget(downbutton_listItem, button_down)
        button_ListWidget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        button_ListWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        button_ListWidget.setMaximumWidth(
            button_ListWidget.sizeHintForColumn(0))

        #############################################
        self.central_widget.setCurrentIndex(1)
        self.main_layout.addWidget(self.central_widget, 1, 1)

        self.setCentralWidget(main_widget)
Beispiel #20
0
class MenuFrame(QFrame):
    def __init__(self, parent):
        super().__init__()

        self.parent = parent

        self.setStyleSheet('background-color: #4B4945')

        menu_img = MenuImage()

        img_widget = QWidget()
        # Horizontal box layout used to add space to both sides of the image
        img_layout = QHBoxLayout()
        img_layout.addStretch(1)
        img_layout.addWidget(menu_img, 2)
        img_layout.addStretch(1)
        img_widget.setLayout(img_layout)

        new_game_btn = MenuButton()
        new_game_btn.setText("New Game")
        new_game_btn.clicked.connect(self.open_dialog)

        load_game_btn = MenuButton()
        load_game_btn.setText("Load Game")
        load_game_btn.clicked.connect(lambda: self.open_dialog(True))

        profile_btn = MenuButton()
        profile_btn.setText("Profile")
        profile_btn.clicked.connect(self.profile_page)

        exit_btn = MenuButton()
        exit_btn.setText("Exit")
        exit_btn.clicked.connect(self.exit)

        button_widget = QWidget()
        # Vertical box layout used to hold the image widget and buttons
        button_layout = QVBoxLayout()
        button_layout.addWidget(img_widget, 2)
        button_layout.addWidget(new_game_btn, 1)
        button_layout.addWidget(load_game_btn, 1)
        button_layout.addWidget(profile_btn, 1)
        button_layout.addWidget(exit_btn, 1)
        button_widget.setLayout(button_layout)

        register_btn = MenuButton()
        register_btn.setText("Register")
        register_btn.clicked.connect(self.register_page)

        login_btn = MenuButton()
        login_btn.setText("Log In")
        login_btn.clicked.connect(self.login_page)

        self.name_label = MenuLabel()

        logout_btn = MenuButton()
        logout_btn.setText("Sign out")
        logout_btn.clicked.connect(self.parent.sign_out)

        self.bottom_left_stack = QStackedWidget()
        self.bottom_left_stack.insertWidget(0, register_btn)
        self.bottom_left_stack.insertWidget(1, self.name_label)
        self.bottom_left_stack.setCurrentIndex(0)

        self.bottom_right_stack = QStackedWidget()
        self.bottom_right_stack.insertWidget(0, login_btn)
        self.bottom_right_stack.insertWidget(1, logout_btn)
        self.bottom_right_stack.setCurrentIndex(0)

        register_widget = QWidget()
        # Vertical box layout used to position the register button
        register_layout = QVBoxLayout()
        register_layout.addStretch(15)
        register_layout.addWidget(self.bottom_left_stack, 1)
        register_widget.setLayout(register_layout)

        login_widget = QWidget()
        # Vertical box layout used to position the login button
        login_layout = QVBoxLayout()
        login_layout.addStretch(15)
        login_layout.addWidget(self.bottom_right_stack, 1)
        login_widget.setLayout(login_layout)

        # Horizontal box layout used to add space to both sides of the image widget and buttons
        menu_layout = QHBoxLayout()
        menu_layout.addWidget(register_widget, 1)
        menu_layout.addStretch(1)
        menu_layout.addWidget(button_widget, 2)
        menu_layout.addStretch(1)
        menu_layout.addWidget(login_widget, 1)
        self.setLayout(menu_layout)

    def open_dialog(self, load_game=False):
        if load_game:
            if not self.parent.user or not self.parent.user.saved_game:
                return
            target_func = self.load_game
        else:
            target_func = self.new_game

        bold_font = QFont()
        bold_font.setBold(True)

        menu = QDialog()
        menu.setWindowIcon(QIcon('./assets/icons/pawn_icon.png'))
        menu.setWindowTitle("Chess")
        menu.setStyleSheet('background-color: #4B4945')

        white_btn = MenuButton()
        white_btn.setText("White")
        white_btn.clicked.connect(menu.accept)

        black_btn = MenuButton()
        black_btn.setText("Black")
        black_btn.clicked.connect(menu.accept)

        player_btn_widget = QWidget()
        player_btn_layout = QHBoxLayout()
        player_btn_layout.addWidget(white_btn)
        player_btn_layout.addWidget(black_btn)
        player_btn_widget.setLayout(player_btn_layout)

        computer_btn = MenuButton(font_scale=40)
        computer_btn.setText("Computer vs Computer")
        computer_btn.clicked.connect(menu.accept)

        computer_btn_widget = QWidget()
        computer_btn_layout = QHBoxLayout()
        computer_btn_layout.addWidget(computer_btn)
        computer_btn_widget.setLayout(computer_btn_layout)

        slider_label = MenuLabel(font_scale=35)
        slider_label.setText("Difficulty")

        slider = QSlider(Qt.Horizontal)
        slider.setMinimum(1)
        slider.setMaximum(5)
        slider.setTickInterval(1)
        slider.setTickPosition(QSlider.TicksBothSides)
        slider.setStyleSheet(
            'QSlider::handle:horizontal {background-color: #E6912C}'
            'QSlider::handle:horizontal:hover {background-color: #D37E19}')

        checkbox = QCheckBox()
        checkbox.setText("Enable autosave")
        checkbox.setFont(bold_font)
        checkbox.setStyleSheet('QCheckBox {color: #E6912C}')

        white_btn.clicked.connect(lambda: target_func('w', slider.value(
        ), checkbox.isChecked(), False))
        black_btn.clicked.connect(lambda: target_func('b', slider.value(
        ), checkbox.isChecked(), False))
        computer_btn.clicked.connect(lambda: target_func(
            None, slider.value(), checkbox.isChecked(), True))

        layout = QVBoxLayout()
        layout.addWidget(player_btn_widget)
        layout.addWidget(computer_btn_widget)
        layout.addWidget(slider_label)
        layout.addWidget(slider)
        if self.parent.user:
            layout.addSpacing(40)
            layout.addWidget(checkbox)
        layout.setSpacing(0)
        menu.setLayout(layout)

        menu.exec_()

    def new_game(self, colour, difficulty, autosave, self_play):
        self.parent.game_frame.info.move_frame.clear_moves()
        self.parent.game_frame.board.set_fen(common.starting_fen)
        self.parent.game_frame.board.user_is_white = True if colour == 'w' else False
        self.parent.game_frame.board.self_play = self_play
        self.parent.game_frame.board.difficulty = difficulty
        self.parent.game_frame.board.autosave = autosave
        self.parent.game_frame.board.start_game()
        self.parent.stack.setCurrentIndex(1)

    def load_game(self, colour, difficulty, autosave, self_play):
        self.parent.game_frame.board.set_position(
            copy.deepcopy(self.parent.user.saved_game))
        self.parent.game_frame.board.saved = True
        self.parent.game_frame.info.move_frame.update_moves()
        self.parent.game_frame.board.user_is_white = True if colour == 'w' else False
        self.parent.game_frame.board.self_play = self_play
        self.parent.game_frame.board.difficulty = difficulty
        self.parent.game_frame.board.autosave = autosave
        self.parent.game_frame.board.start_game()
        self.parent.stack.setCurrentIndex(1)

    def profile_page(self):
        if self.parent.user:
            self.parent.profile_frame.update()
            self.parent.stack.setCurrentIndex(2)

    def exit(self):
        self.parent.close()

    def register_page(self):
        self.parent.stack.setCurrentIndex(3)

    def login_page(self):
        self.parent.stack.setCurrentIndex(4)
Beispiel #21
0
class ComprehensionTestApp(QMainWindow):
    """
	@modifies self.symbol_test, self.question1, self.question2
	@effects makes a new ComprehensionTestApp
	"""
    def __init__(self):
        super().__init__()
        self.symbol_tests = QStackedWidget()
        self.question1 = "Exactly what do you think this symbol means?"
        self.question2 = "What action would you take in response to this symbol?"
        self.init_gui()

    """
	@modifies self
	@effects sets up the main window
	"""

    def init_gui(self):
        exitAct = QAction('&Exit', self)
        exitAct.setShortcut('Ctrl+Q')
        exitAct.setStatusTip('Exit application')
        exitAct.triggered.connect(self.quit)

        saveAct = QAction('&Save as PDF', self)
        saveAct.setShortcut('Ctrl+S')
        saveAct.setStatusTip('Saves as PDF')
        saveAct.triggered.connect(self.save_as_pdf)

        importAct = QAction('&Import symbols', self)
        importAct.setShortcut('Ctrl+I')
        importAct.setStatusTip(
            'Imports all the specified images on to their own test page')
        importAct.triggered.connect(self.import_symbols)

        menu_bar = self.menuBar()
        filemenu = menu_bar.addMenu('&File')
        filemenu.addAction(importAct)
        filemenu.addAction(saveAct)
        filemenu.addAction(exitAct)

        goToAct = QAction('&Go to page', self)
        goToAct.setStatusTip('Go to the specified page')
        goToAct.setShortcut('Ctrl+G')
        goToAct.triggered.connect(self.go_to_page)

        newQuestAct = QAction('&Change default questions', self)
        newQuestAct.setStatusTip(
            'Changes the default questions asked about the symbol')
        newQuestAct.setShortcut('Ctrl+H')
        newQuestAct.triggered.connect(self.change_questions)

        moveLeftAct = QAction('&Move current page left', self)
        moveLeftAct.setShortcut('Ctrl+,')
        moveLeftAct.setStatusTip('Moves the current page one page to the left')
        moveLeftAct.triggered.connect(self.move_test_left)

        moveRightAct = QAction('&Move current page right', self)
        moveRightAct.setShortcut('Ctrl+.')
        moveRightAct.setStatusTip(
            'Moves the current page one page to the right')
        moveRightAct.triggered.connect(self.move_test_right)

        moveToAct = QAction('Move current page to', self)
        moveToAct.setShortcut('Ctrl+M')
        moveToAct.setStatusTip('Moves the current page to the specified page')
        moveToAct.triggered.connect(self.move_to_page)

        delPagesAct = QAction('Delete pages', self)
        delPagesAct.setShortcut('Ctrl+D')
        delPagesAct.setStatusTip('Deletes the specified pages')
        delPagesAct.triggered.connect(self.delete_pages)

        editmenu = menu_bar.addMenu('&Edit')
        editmenu.addAction(delPagesAct)
        editmenu.addAction(newQuestAct)
        editmenu.addAction(goToAct)
        editmenu.addAction(moveLeftAct)
        editmenu.addAction(moveRightAct)
        editmenu.addAction(moveToAct)

        nextAct = QAction(QIcon("next.png"), 'Next page (Ctrl+P)', self)
        nextAct.setShortcut('Ctrl+P')
        nextAct.setStatusTip('Goes to the next page')
        nextAct.triggered.connect(self.next_page)

        prevAct = QAction(QIcon("prev.png"), "Previous page (Ctrl+O)", self)
        prevAct.setShortcut('Ctrl+O')
        prevAct.setStatusTip('Goes to the previous page')
        prevAct.triggered.connect(self.prev_page)

        newAct = QAction(QIcon("add.png"), "Add a new page (Ctrl+N)", self)
        newAct.setShortcut('Ctrl+N')
        newAct.setStatusTip('Creates a new page')
        newAct.triggered.connect(self.add_blank_test)

        remAct = QAction(QIcon("remove.png"), "Delete page (Ctrl+R)", self)
        remAct.setShortcut('Ctrl+R')
        remAct.setStatusTip('Deletes the current page')
        remAct.triggered.connect(self.delete_test)

        tool_bar = self.addToolBar("Next Page")
        tool_bar.addAction(prevAct)
        tool_bar.addAction(nextAct)
        tool_bar.addAction(newAct)
        tool_bar.addAction(remAct)

        self.setWindowTitle("Open Comprehension Test Generator")
        self.setWindowIcon(QIcon("rubber ducky.png"))
        self.setGeometry(500, 500, 500, 450)
        self.add_blank_test()
        self.setCentralWidget(self.symbol_tests)

        self.show()

    """
	@modifies none
	@effects  confirms if the user wishes to exit
	"""

    def closeEvent(self, event):
        msg = QMessageBox.question(self, 'Message', "Really quit?",
                                   QMessageBox.Yes | QMessageBox.No,
                                   QMessageBox.No)
        if msg == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

    """
	@modifies none
	@effects  confirms if the user wishes to exit
	"""

    def quit(self):
        msg = QMessageBox.question(self, 'Message', "Really quit?",
                                   QMessageBox.Yes | QMessageBox.No,
                                   QMessageBox.No)
        if msg == QMessageBox.Yes:
            qApp.quit()

    """
	@modifies self.symbol_tests
	@effects  adds a blank symbol_test to the end of symbol_tests
			  sets the current symbol_test to the new one
	"""

    def add_blank_test(self):
        page = self.symbol_tests.count() + 1
        test = SymbolTestWidget(
            self,
            comp_questions=[self.question1, self.question2],
            pageNumber=page,
            pageTotal=page)
        test.set_visual_context("blank image.png")
        self.symbol_tests.addWidget(test)
        self.symbol_tests.setCurrentIndex(page - 1)
        for i in range(0, self.symbol_tests.count() - 1):
            self.symbol_tests.widget(i).set_numPages(self.symbol_tests.count())

    """
	@modifies self.symbol_tests
	@effects  changes the current symbol_test to the next one
	"""

    def next_page(self):
        if self.symbol_tests.currentIndex() < self.symbol_tests.count() - 1:
            self.symbol_tests.setCurrentIndex(
                self.symbol_tests.currentIndex() + 1)

    """
	@modifies self.symbol_test
	@effects  changes the current symbol_test to the previous one
	"""

    def prev_page(self):
        if self.symbol_tests.currentIndex() > 0:
            self.symbol_tests.setCurrentIndex(
                self.symbol_tests.currentIndex() - 1)

    """
	@modifies none
	@effects  saves all the symbol_tests as seperate pages on a PDF document
	"""

    def save_as_pdf(self):
        filename = QFileDialog.getSaveFileName(self, 'Save to PDF', 'c:\\',
                                               "*.pdf")

        if filename != ('', ''):
            if os.path.exists(filename[0]):
                try:
                    infile = PdfFileReader(filename[0], 'rb')
                except:
                    error = QMessageBox()
                    error.setIcon(QMessageBox.Warning)
                    error.setStandardButtons(QMessageBox.Ok)
                    error.setText(
                        "File could not be written to. If the file is currently open, try closing it"
                    )
                    error.exec_()
                    return
                if infile.getNumPages() == 0:
                    print("HERE!")
                    doc = QTextDocument()
                    doc.print(printer)

            printer = QPrinter()
            printer.setPageSize(QPrinter.A4)
            printer.setOutputFormat(QPrinter.PdfFormat)
            printer.setOutputFileName(filename[0])

            painter = QPainter()

            font = QFont("times")
            font.setPointSize(12)

            x = painter.begin(printer)
            if x == False:
                error = QMessageBox()
                error.setIcon(QMessageBox.Warning)
                error.setStandardButtons(QMessageBox.Ok)
                error.setText(
                    "File could not be saved. If the file is currently open, try closing it"
                )
                error.exec_()
                return
            painter.setFont(font)

            for i in range(0, self.symbol_tests.count()):
                cur_symbol_test = self.symbol_tests.widget(i)

                if cur_symbol_test.print_visual_context() == False:
                    pixmap = cur_symbol_test.get_symbol()
                    pixmap = pixmap.scaled(350, 350)

                    painter.drawPixmap(30, 100, pixmap)
                    painter.drawText(750, 20, cur_symbol_test.get_page())
                    painter.drawText(
                        420, 200, 350, 400, QtCore.Qt.TextWordWrap,
                        "Context: " + cur_symbol_test.get_context())
                    painter.drawText(30, 600, cur_symbol_test.get_question1())
                    painter.drawText(30, 830, cur_symbol_test.get_question2())

                    cur_pen = painter.pen()
                    line_pen = QPen()
                    line_pen.setWidth(2)
                    painter.setPen(line_pen)
                    painter.drawLine(70, 656, 600, 656)
                    painter.drawLine(70, 712, 600, 712)
                    painter.drawLine(70, 768, 600, 768)

                    painter.drawLine(70, 886, 600, 886)
                    painter.drawLine(70, 942, 600, 942)
                    painter.drawLine(70, 998, 600, 998)
                    painter.setPen(cur_pen)

                else:
                    pixmap = cur_symbol_test.get_visual_context()
                    pixmap = pixmap.scaled(300, 300)

                    painter.drawPixmap(200, 10, pixmap)

                    pixmap = cur_symbol_test.get_symbol()
                    pixmap = pixmap.scaled(250, 250)

                    painter.drawPixmap(225, 320, pixmap)

                    painter.drawText(750, 20, cur_symbol_test.get_page())
                    #painter.drawText(420, 200, 350, 400, QtCore.Qt.TextWordWrap, "Context: " + cur_symbol_test.get_context())
                    painter.drawText(30, 600, cur_symbol_test.get_question1())
                    painter.drawText(30, 830, cur_symbol_test.get_question2())

                    cur_pen = painter.pen()
                    line_pen = QPen()
                    line_pen.setWidth(2)
                    painter.setPen(line_pen)
                    painter.drawLine(70, 656, 600, 656)
                    painter.drawLine(70, 712, 600, 712)
                    painter.drawLine(70, 768, 600, 768)

                    painter.drawLine(70, 886, 600, 886)
                    painter.drawLine(70, 942, 600, 942)
                    painter.drawLine(70, 998, 600, 998)
                    painter.setPen(cur_pen)
                if (i < self.symbol_tests.count() - 1):
                    printer.newPage()

            painter.end()

    """
	@modifies self.symbol_tests
	@effects  adds all the specified symbols to their own symbol_test and adds those
			  tests to self.symbol_tests
	"""

    def import_symbols(self):
        fnames = QFileDialog.getOpenFileNames(self, 'Open file', 'c:\\',
                                              "Image files (*.jpg *.png)")
        if fnames != ([], ''):
            for i in range(0, len(fnames[0])):
                page = self.symbol_tests.count() + 1
                test = SymbolTestWidget(
                    self,
                    comp_questions=[self.question1, self.question2],
                    pageNumber=page,
                    pageTotal=page)
                test.set_symbol(fnames[0][i])
                test.set_visual_context("blank image.png")
                self.symbol_tests.addWidget(test)
            self.symbol_tests.setCurrentIndex(page - 1)

            for i in range(0, self.symbol_tests.count()):
                self.symbol_tests.widget(i).set_numPages(
                    self.symbol_tests.count())

    """
	@modifies self.symbol_tests
	@effects  removes the current test from self.symbol_tests
	"""

    def delete_test(self):
        msg = QMessageBox.question(self, 'Message', "Delete test?",
                                   QMessageBox.Yes | QMessageBox.No,
                                   QMessageBox.No)
        if msg == QMessageBox.No:
            return

        if self.symbol_tests.currentIndex() != 0:
            cur_idx = self.symbol_tests.currentIndex()
            self.symbol_tests.setCurrentIndex(cur_idx - 1)
            self.symbol_tests.removeWidget(self.symbol_tests.widget(cur_idx))
            for i in range(0, self.symbol_tests.count()):
                cur_symbol_test = self.symbol_tests.widget(i)
                cur_symbol_test.set_numPages(self.symbol_tests.count())

                if i >= cur_idx:
                    cur_symbol_test.set_page(i + 1)

        elif self.symbol_tests.currentIndex(
        ) == 0 and self.symbol_tests.count() > 1:
            self.symbol_tests.setCurrentIndex(1)
            self.symbol_tests.removeWidget(self.symbol_tests.widget(0))
            for i in range(0, self.symbol_tests.count()):
                cur_symbol_test = self.symbol_tests.widget(i)
                cur_symbol_test.set_numPages(self.symbol_tests.count())
                cur_symbol_test.set_page(i + 1)

        elif self.symbol_tests.currentIndex() == 0 and self.symbol_tests.count(
        ) == 1:
            page = 1
            test = SymbolTestWidget(
                self,
                comp_questions=[self.question1, self.question2],
                pageNumber=page,
                pageTotal=page)
            self.symbol_tests.addWidget(test)
            self.symbol_tests.setCurrentIndex(1)
            self.symbol_tests.removeWidget(self.symbol_tests.widget(0))

    """
	@modifies self.symbol_tests
	@effects  decreases the current symbol_test's index in self.symbol_tests by 1,
			  moves it down 1 postion
	"""

    def move_test_left(self):
        cur_idx = self.symbol_tests.currentIndex()
        if cur_idx > 0:
            cur_widget = self.symbol_tests.widget(cur_idx)
            prev_widget = self.symbol_tests.widget(cur_idx - 1)
            cur_widget.set_page(int(cur_widget.get_page()) - 1)
            prev_widget.set_page(int(prev_widget.get_page()) + 1)

            self.symbol_tests.removeWidget(prev_widget)
            self.symbol_tests.insertWidget(
                self.symbol_tests.indexOf(cur_widget) + 1, prev_widget)

    """
	@modifies self.symbol_tests
	@effects  increases the current symbol_test's index in self.symbol_tests by 1,
			  moves it up 1 postion
	"""

    def move_test_right(self):
        cur_idx = self.symbol_tests.currentIndex()
        if cur_idx < self.symbol_tests.count() - 1:
            cur_widget = self.symbol_tests.widget(cur_idx)
            next_widget = self.symbol_tests.widget(cur_idx + 1)
            cur_widget.set_page(int(cur_widget.get_page()) + 1)
            next_widget.set_page(int(next_widget.get_page()) - 1)

            self.symbol_tests.removeWidget(next_widget)
            self.symbol_tests.insertWidget(
                self.symbol_tests.indexOf(cur_widget), next_widget)

    """
	@modifies self.symbol_tests
	@effects  moves the current symbol_test to a specified position in self.symbol_tests
	"""

    def move_to_page(self):
        text = QInputDialog.getText(self, "Move Page",
                                    "Move current page to: ", QLineEdit.Normal)
        if text[1] != False:
            try:
                x = int(text[0])
                if x <= 0 or x > self.symbol_tests.count():
                    error = QMessageBox()
                    error.setIcon(QMessageBox.Warning)
                    error.setStandardButtons(QMessageBox.Ok)
                    error.setText("Page must be between 1 and " +
                                  str(self.symbol_tests.count()))
                    error.exec_()
                    return

                cur_idx = self.symbol_tests.currentIndex()
                cur_widget = self.symbol_tests.widget(cur_idx)
                cur_widget.set_page(x - 1)

                self.symbol_tests.removeWidget(cur_widget)
                self.symbol_tests.insertWidget(x - 1, cur_widget)
                self.symbol_tests.setCurrentIndex(x - 1)

                for i in range(0, self.symbol_tests.count()):
                    loop_widget = self.symbol_tests.widget(i)
                    loop_widget.set_page(i + 1)

            except ValueError:
                error = QMessageBox()
                error.setIcon(QMessageBox.Warning)
                error.setStandardButtons(QMessageBox.Ok)
                error.setText("Can only enter an integer between 1 and " +
                              str(self.symbol_tests.count()))
                error.exec_()

    """
	@modifies self.symbol_tests
	@effects  sets the surrent symbol_test equal to the one at the specified page
	"""

    def go_to_page(self):
        text = QInputDialog.getText(self, "Go to", "Go to page: ",
                                    QLineEdit.Normal)
        if text[1] != False:
            try:
                x = int(text[0])
                if x <= 0 or x > self.symbol_tests.count():
                    error = QMessageBox()
                    error.setIcon(QMessageBox.Warning)
                    error.setStandardButtons(QMessageBox.Ok)
                    error.setText("Page must be between 1 and " +
                                  str(self.symbol_tests.count()))
                    error.exec_()
                    return

                self.symbol_tests.setCurrentIndex(x - 1)
            except ValueError:
                error = QMessageBox()
                error.setIcon(QMessageBox.Warning)
                error.setStandardButtons(QMessageBox.Ok)
                error.setText("Can only enter an integer between 1 and " +
                              str(self.symbol_tests.count()))
                error.exec_()

    """
	@modifies self.question1, self.question2
	@effects  changes the default questions
	"""

    def change_questions(self):
        text = QInputDialog.getText(self, "Question 1 Input", "Question 1: ",
                                    QLineEdit.Normal, self.question1)
        if str(text[0]) != '':
            self.question1 = str(text[0])
        text = QInputDialog.getText(self, "Question 2 Input", "Question 2: ",
                                    QLineEdit.Normal, self.question2)
        if str(text[0]) != '':
            self.question2 = str(text[0])

    def delete_pages(self):
        text = QInputDialog.getText(
            self, "Delete pages", "Enter page numbers seperated by a comma:",
            QLineEdit.Normal)
        error = QMessageBox()
        error.setIcon(QMessageBox.Warning)
        error.setStandardButtons(QMessageBox.Ok)
        if text[1] != False:
            pages = text[0].split(",")
            del_widgets = []
            for page in pages:
                try:
                    x = int(page)
                except:
                    error.setText("All page numbers must be integers")
                    error.exec_()
                    return
                if int(page) > self.symbol_tests.count() or int(page) < 1:
                    error.setText("Page " + page + " does not exist")
                    error.exec_()
                    return
                del_widgets.append(self.symbol_tests.widget(int(page) - 1))

            confirm = QMessageBox.question(
                self, 'Message', "Really delete pages: " + text[0] + "?",
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

            for del_widget in del_widgets:
                del_idx = self.symbol_tests.indexOf(del_widget)
                if del_idx != self.symbol_tests.currentIndex():
                    self.symbol_tests.removeWidget(del_widget)
                else:
                    #Removing the only test
                    if self.symbol_tests.count() == 1:
                        self.add_blank_test()
                        self.symbol_tests.removeWidget(del_widget)
                        self.symbol_tests.currentWidget().set_page(1)
                        self.symbol_tests.currentWidget().set_numPages(1)
                        return
                    else:
                        if del_idx == self.symbol_tests.count() - 1:
                            self.symbol_tests.setCurrentIndex(del_idx - 1)
                            self.symbol_tests.removeWidget(del_widget)
                        else:
                            self.symbol_tests.setCurrentIndex(del_idx + 1)
                            self.symbol_tests.removeWidget(del_widget)

            count = 1
            for i in range(0, self.symbol_tests.count()):
                cur_widget = self.symbol_tests.widget(i)
                cur_widget.set_page(count)
                cur_widget.set_numPages(self.symbol_tests.count())
                count += 1
Beispiel #22
0
class TabStackedWidget(QWidget):
    '''
    @note: just some of QTabWidget's methods were implemented
    '''
    def __init__(self, parent=None):
        super(TabStackedWidget, self).__init__(parent)
        self._stack = None  # QStackedWidget
        self._tabBar = None  # ComboTabBar
        self._mainLayout = None  # QVBoxLayout
        self._dirtyTabBar = False

        self._currentIndex = 0
        self._previousIndex = 0

        self._stack = QStackedWidget(self)
        self._mainLayout = QVBoxLayout()
        self._mainLayout.setSpacing(0)
        self._mainLayout.setContentsMargins(0, 0, 0, 0)

        self._mainLayout.addWidget(self._stack)
        self.setLayout(self._mainLayout)

        self._stack.widgetRemoved.connect(self._tabWasRemoved)

    def tabBar(self):
        '''
        @return: ComboTabBar
        '''
        return self._tabBar

    def setTabBar(self, tb):
        '''
        @param: ComboTabBar
        '''
        assert (tb)

        if tb.parentWidget() != self:
            tb.setParent(self)
            tb.show()

        del self._tabBar
        self._dirtyTabBar = True
        self._tabBar = tb
        self.setFocusProxy(self._tabBar)

        self._tabBar.currentChanged.connect(self._showTab)
        self._tabBar.tabMoved.connect(
            lambda from_, to_: TabStackedWidget._tabWasMoved(self, from_, to_))
        self._tabBar.overFlowChanged.connect(self.setUpLayout)

        if self._tabBar.tabsCloseable():
            self._tabBar.tabCloseRequested.connect(self.tabCloseRequested)

        self.setDocumentMode(self._tabBar.documentMode())

        self._tabBar.installEventFilter(self)
        self.setUpLayout()

    def documentMode(self):
        return self._tabBar.documentMode()

    def setDocumentMode(self, enabled):
        self._tabBar.setDocumentModel(enabled)
        self._tabBar.setExpanding(not enabled)
        self._tabBar.setDrawBase(enabled)

    def addTab(self, widget, label, pinned=False):
        '''
        @return: int
        '''
        return self.insertTab(-1, widget, label, pinned)

    def insertTab(self, index, widget, label, pinned=False):
        '''
        @param: widget QWidget
        @param: label QString
        '''
        if not widget:
            return -1

        if pinned:
            if index < 0:
                index = self._tabBar.pinnedTabsCount()
            else:
                index = min(index, self._tabBar.pinnedTabsCount())
            index = self._stack.insertWidget(index, widget)
            self._tabBar.insertTabByIconText(index, QIcon(), label, True)
        else:
            if index < 0:
                index = self._tabBar.pinnedTabsCount()
            else:
                index = max(index, self._tabBar.pinnedTabsCount())
            index = self._stack.insertWidget(index, widget)
            self._tabBar.insertTabByIconText(index, QIcon(), label, False)

        if self._previousIndex >= index:
            self._previousIndex += 1
        if self._currentIndex >= index:
            self._currentIndex += 1

        QTimer.singleShot(0, self.setUpLayout)

        return index

    def tabText(self, index):
        return self._tabBar.tabText(index)

    def setTabText(self, index, label):
        self._tabBar.setTabText(index, label)

    def tabToolTip(self, index):
        return self._tabBar.tabToolTip(index)

    def setTabToolTip(self, index, tip):
        self._tabBar.setTabToolTip(index, tip)

    def pinUnPinTab(self, index, title=''):
        widget = self._stack.widget(index)
        currentWidget = self._stack.currentWidget()

        if not widget or not currentWidget:
            return -1

        makePinned = index >= self._tabBar.pinnedTabsCount()
        button = self._tabBar.tabButton(index,
                                        self._tabBar.iconButtonPosition())
        # To show tooltip of tab which is pinned in the current session
        toolTip = self.tabToolTip(index)

        self._tabBar._blockCurrentChangedSignal = True
        self._tabBar.setTabButton(index, self._tabBar.iconButtonPosition(),
                                  None)

        self._stack.removeWidget(widget)
        if makePinned:
            insertIndex = 0
        else:
            insertIndex = self._tabBar.pinnedTabsCount()
        newIndex = self.insertTab(insertIndex, widget, title, makePinned)

        self._tabBar.setTabButton(newIndex, self._tabBar.iconButtonPosition(),
                                  button)
        self._tabBar._blockCurrentChangedSignal = False
        self.setTabToolTip(newIndex, toolTip)

        # Restore current widget
        self.setCurrentWidget(currentWidget)

        self.pinStateChanged.emit(newIndex, makePinned)

        return newIndex

    def removeTab(self, index):
        widget = self._stack.widget(index)
        if widget:
            # Select another current tab before remove, so it won't be handled
            # by QTabBar
            if index == self.currentIndex() and self.count() > 1:
                self._selectTabOnRemove()
            self._stack.removeWidget(widget)

    def moveTab(self, from_, to_):
        self._tabBar.moveTab(from_, to_)

    def currentIndex(self):
        '''
        @return: int
        '''
        return self._tabBar.currentIndex()

    def currentWidget(self):
        '''
        @return: QWidget
        '''
        return self._stack.currentWidget()

    def widget(self, index):
        '''
        @return: QWidget
        '''
        return self._stack.widget(index)

    def indexOf(self, widget):
        '''
        @param: widget QWidget
        @return: int
        '''
        return self._stack.indexOf(widget)

    def count(self):
        return self._tabBar.count()

    # Q_SIGNALS
    currentChanged = pyqtSignal(int)  # index
    tabCloseRequested = pyqtSignal(int)  # index
    pinStateChanged = pyqtSignal(int, bool)  # index, pinned

    # public Q_SLOTS
    def setCurrentIndex(self, index):
        self._tabBar.setCurrentIndex(index)

    def setCurrentWidget(self, widget):
        '''
        @widget: widget QWidget
        '''
        self._tabBar.setCurrentIndex(self.indexOf(widget))

    def setUpLayout(self):
        if not self._tabBar.isVisible():
            self._dirtyTabBar = True
            return

        self._tabBar.setElideMode(self._tabBar.elideMode())
        self._dirtyTabBar = False

    # private Q_SLOTS
    def _showTab(self, index):
        if self._validIndex(index):
            self._stack.setCurrentIndex(index)

        self._previousIndex = self._currentIndex
        self._currentIndex = index

        # This is slot connected to ComboTabBar::currentChanged
        # We must send the signal event with invalid index (-1)
        self.currentChanged.emit(index)

    def _tabWasMoved(self, from_, to_):
        self._stack.blockSignals(True)
        widget = self._stack.widget(from_)
        self._stack.removeWidget(widget)
        self._stack.insertWidget(to_, widget)
        self._stack.blockSignals(False)

    def _tabWasRemoved(self, index):
        if self._previousIndex == index:
            self._previousIndex = -1
        elif self._previousIndex > index:
            self._previousIndex -= 1

        if self._currentIndex == index:
            self._currentIndex = -1
        elif self._currentIndex > index:
            self._currentIndex -= 1

        self._tabBar.removeTab(index)

    # protected:
    # override
    def eventFilter(self, obj, event):
        '''
        @param: obj QObject
        @param: event QEvent
        @return: bool
        '''
        if self._dirtyTabBar and obj == self._tabBar and event.type(
        ) == QEvent.Show:
            self.setUpLayout()

        return False

    # override
    def keyPressEvent(self, event):
        '''
        @param: event QKeyEvent
        '''
        evkey = event.key()
        evmodifiers = event.modifiers()
        if evkey == Qt.Key_Tab or evkey == Qt.Key_Backtab and \
                self.count() > 1 and evmodifiers & Qt.ControlModifier:
            pageCount = self.count()
            page = self.currentIndex()
            if (evkey == Qt.Key_Backtab) or (evmodifiers & Qt.ShiftModifier):
                dx = -1
            else:
                dx = 1
            for idx in range(pageCount):
                page += dx
                if page < 0:
                    page = self.count() - 1
                elif page >= pageCount:
                    page = 0
                if self._tabBar.isTabEnabled(page):
                    self.setCurrentIndex(page)
                    break
            if not QApplication.focusWidget():
                self._tabBar.setFocus()
        else:
            event.ignore()

    # private:
    def _validIndex(self, index):
        return index < self._stack.count() and index >= 0

    def _selectTabOnRemove(self):
        assert (self.count() > 1)

        index = -1

        behavior = self._tabBar.selectionBehaviorOnRemove()
        if behavior == QTabBar.SelectPreviousTab:
            if self._validIndex(self._previousIndex):
                index = self._previousIndex
            # fallthrough
        elif behavior == QTabBar.SelectLeftTab:
            index = self.currentIndex() - 1
            if not self._validIndex(index):
                index = 1
        elif behavior == QTabBar.SelectRightTab:
            index = self.currentIndex() + 1
            if not self._validIndex(index):
                index = self.currentIndex() - 1

        assert (self._validIndex(index))
        self.setCurrentIndex(index)
Beispiel #23
0
class E5SideBar(QWidget):
    """
    Class implementing a sidebar with a widget area, that is hidden or shown,
    if the current tab is clicked again.
    """
    Version = 1
    
    North = 0
    East = 1
    South = 2
    West = 3
    
    def __init__(self, orientation=None, delay=200, parent=None):
        """
        Constructor
        
        @param orientation orientation of the sidebar widget (North, East,
            South, West)
        @param delay value for the expand/shrink delay in milliseconds
            (integer)
        @param parent parent widget (QWidget)
        """
        super(E5SideBar, self).__init__(parent)
        
        self.__tabBar = QTabBar()
        self.__tabBar.setDrawBase(True)
        self.__tabBar.setShape(QTabBar.RoundedNorth)
        self.__tabBar.setUsesScrollButtons(True)
        self.__tabBar.setDrawBase(False)
        self.__stackedWidget = QStackedWidget(self)
        self.__stackedWidget.setContentsMargins(0, 0, 0, 0)
        self.__autoHideButton = QToolButton()
        self.__autoHideButton.setCheckable(True)
        self.__autoHideButton.setIcon(
            UI.PixmapCache.getIcon("autoHideOff.png"))
        self.__autoHideButton.setChecked(True)
        self.__autoHideButton.setToolTip(
            self.tr("Deselect to activate automatic collapsing"))
        self.barLayout = QBoxLayout(QBoxLayout.LeftToRight)
        self.barLayout.setContentsMargins(0, 0, 0, 0)
        self.layout = QBoxLayout(QBoxLayout.TopToBottom)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        self.barLayout.addWidget(self.__autoHideButton)
        self.barLayout.addWidget(self.__tabBar)
        self.layout.addLayout(self.barLayout)
        self.layout.addWidget(self.__stackedWidget)
        self.setLayout(self.layout)
        
        # initialize the delay timer
        self.__actionMethod = None
        self.__delayTimer = QTimer(self)
        self.__delayTimer.setSingleShot(True)
        self.__delayTimer.setInterval(delay)
        self.__delayTimer.timeout.connect(self.__delayedAction)
        
        self.__minimized = False
        self.__minSize = 0
        self.__maxSize = 0
        self.__bigSize = QSize()
        
        self.splitter = None
        self.splitterSizes = []
        
        self.__hasFocus = False
        # flag storing if this widget or any child has the focus
        self.__autoHide = False
        
        self.__tabBar.installEventFilter(self)
        
        self.__orientation = E5SideBar.North
        if orientation is None:
            orientation = E5SideBar.North
        self.setOrientation(orientation)
        
        self.__tabBar.currentChanged[int].connect(
            self.__stackedWidget.setCurrentIndex)
        e5App().focusChanged[QWidget, QWidget].connect(self.__appFocusChanged)
        self.__autoHideButton.toggled[bool].connect(self.__autoHideToggled)
    
    def setSplitter(self, splitter):
        """
        Public method to set the splitter managing the sidebar.
        
        @param splitter reference to the splitter (QSplitter)
        """
        self.splitter = splitter
        self.splitter.splitterMoved.connect(self.__splitterMoved)
        self.splitter.setChildrenCollapsible(False)
        index = self.splitter.indexOf(self)
        self.splitter.setCollapsible(index, False)
    
    def __splitterMoved(self, pos, index):
        """
        Private slot to react on splitter moves.
        
        @param pos new position of the splitter handle (integer)
        @param index index of the splitter handle (integer)
        """
        if self.splitter:
            self.splitterSizes = self.splitter.sizes()
    
    def __delayedAction(self):
        """
        Private slot to handle the firing of the delay timer.
        """
        if self.__actionMethod is not None:
            self.__actionMethod()
    
    def setDelay(self, delay):
        """
        Public method to set the delay value for the expand/shrink delay in
        milliseconds.
        
        @param delay value for the expand/shrink delay in milliseconds
            (integer)
        """
        self.__delayTimer.setInterval(delay)
    
    def delay(self):
        """
        Public method to get the delay value for the expand/shrink delay in
        milliseconds.
        
        @return value for the expand/shrink delay in milliseconds (integer)
        """
        return self.__delayTimer.interval()
    
    def __cancelDelayTimer(self):
        """
        Private method to cancel the current delay timer.
        """
        self.__delayTimer.stop()
        self.__actionMethod = None
    
    def shrink(self):
        """
        Public method to record a shrink request.
        """
        self.__delayTimer.stop()
        self.__actionMethod = self.__shrinkIt
        self.__delayTimer.start()
   
    def __shrinkIt(self):
        """
        Private method to shrink the sidebar.
        """
        self.__minimized = True
        self.__bigSize = self.size()
        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            self.__minSize = self.minimumSizeHint().height()
            self.__maxSize = self.maximumHeight()
        else:
            self.__minSize = self.minimumSizeHint().width()
            self.__maxSize = self.maximumWidth()
        if self.splitter:
            self.splitterSizes = self.splitter.sizes()
        
        self.__stackedWidget.hide()
        
        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            self.setFixedHeight(self.__tabBar.minimumSizeHint().height())
        else:
            self.setFixedWidth(self.__tabBar.minimumSizeHint().width())
        
        self.__actionMethod = None
    
    def expand(self):
        """
        Public method to record a expand request.
        """
        self.__delayTimer.stop()
        self.__actionMethod = self.__expandIt
        self.__delayTimer.start()
    
    def __expandIt(self):
        """
        Private method to expand the sidebar.
        """
        self.__minimized = False
        self.__stackedWidget.show()
        self.resize(self.__bigSize)
        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            minSize = max(self.__minSize, self.minimumSizeHint().height())
            self.setMinimumHeight(minSize)
            self.setMaximumHeight(self.__maxSize)
        else:
            minSize = max(self.__minSize, self.minimumSizeHint().width())
            self.setMinimumWidth(minSize)
            self.setMaximumWidth(self.__maxSize)
        if self.splitter:
            self.splitter.setSizes(self.splitterSizes)
        
        self.__actionMethod = None
    
    def isMinimized(self):
        """
        Public method to check the minimized state.
        
        @return flag indicating the minimized state (boolean)
        """
        return self.__minimized
    
    def isAutoHiding(self):
        """
        Public method to check, if the auto hide function is active.
        
        @return flag indicating the state of auto hiding (boolean)
        """
        return self.__autoHide
    
    def eventFilter(self, obj, evt):
        """
        Public method to handle some events for the tabbar.
        
        @param obj reference to the object (QObject)
        @param evt reference to the event object (QEvent)
        @return flag indicating, if the event was handled (boolean)
        """
        if obj == self.__tabBar:
            if evt.type() == QEvent.MouseButtonPress:
                pos = evt.pos()
                for i in range(self.__tabBar.count()):
                    if self.__tabBar.tabRect(i).contains(pos):
                        break
                
                if i == self.__tabBar.currentIndex():
                    if self.isMinimized():
                        self.expand()
                    else:
                        self.shrink()
                    return True
                elif self.isMinimized():
                    self.expand()
            elif evt.type() == QEvent.Wheel:
                if qVersion() >= "5.0.0":
                    delta = evt.angleDelta().y()
                else:
                    delta = evt.delta()
                if delta > 0:
                    self.prevTab()
                else:
                    self.nextTab()
                return True
        
        return QWidget.eventFilter(self, obj, evt)
    
    def addTab(self, widget, iconOrLabel, label=None):
        """
        Public method to add a tab to the sidebar.
        
        @param widget reference to the widget to add (QWidget)
        @param iconOrLabel reference to the icon or the label text of the tab
            (QIcon, string)
        @param label the labeltext of the tab (string) (only to be
            used, if the second parameter is a QIcon)
        """
        if label:
            index = self.__tabBar.addTab(iconOrLabel, label)
            self.__tabBar.setTabToolTip(index, label)
        else:
            index = self.__tabBar.addTab(iconOrLabel)
            self.__tabBar.setTabToolTip(index, iconOrLabel)
        self.__stackedWidget.addWidget(widget)
        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            self.__minSize = self.minimumSizeHint().height()
        else:
            self.__minSize = self.minimumSizeHint().width()
    
    def insertTab(self, index, widget, iconOrLabel, label=None):
        """
        Public method to insert a tab into the sidebar.
        
        @param index the index to insert the tab at (integer)
        @param widget reference to the widget to insert (QWidget)
        @param iconOrLabel reference to the icon or the labeltext of the tab
            (QIcon, string)
        @param label the labeltext of the tab (string) (only to be
            used, if the second parameter is a QIcon)
        """
        if label:
            index = self.__tabBar.insertTab(index, iconOrLabel, label)
            self.__tabBar.setTabToolTip(index, label)
        else:
            index = self.__tabBar.insertTab(index, iconOrLabel)
            self.__tabBar.setTabToolTip(index, iconOrLabel)
        self.__stackedWidget.insertWidget(index, widget)
        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            self.__minSize = self.minimumSizeHint().height()
        else:
            self.__minSize = self.minimumSizeHint().width()
    
    def removeTab(self, index):
        """
        Public method to remove a tab.
        
        @param index the index of the tab to remove (integer)
        """
        self.__stackedWidget.removeWidget(self.__stackedWidget.widget(index))
        self.__tabBar.removeTab(index)
        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            self.__minSize = self.minimumSizeHint().height()
        else:
            self.__minSize = self.minimumSizeHint().width()
    
    def clear(self):
        """
        Public method to remove all tabs.
        """
        while self.count() > 0:
            self.removeTab(0)
    
    def prevTab(self):
        """
        Public slot used to show the previous tab.
        """
        ind = self.currentIndex() - 1
        if ind == -1:
            ind = self.count() - 1
            
        self.setCurrentIndex(ind)
        self.currentWidget().setFocus()
    
    def nextTab(self):
        """
        Public slot used to show the next tab.
        """
        ind = self.currentIndex() + 1
        if ind == self.count():
            ind = 0
            
        self.setCurrentIndex(ind)
        self.currentWidget().setFocus()
    
    def count(self):
        """
        Public method to get the number of tabs.
        
        @return number of tabs in the sidebar (integer)
        """
        return self.__tabBar.count()
    
    def currentIndex(self):
        """
        Public method to get the index of the current tab.
        
        @return index of the current tab (integer)
        """
        return self.__stackedWidget.currentIndex()
    
    def setCurrentIndex(self, index):
        """
        Public slot to set the current index.
        
        @param index the index to set as the current index (integer)
        """
        self.__tabBar.setCurrentIndex(index)
        self.__stackedWidget.setCurrentIndex(index)
        if self.isMinimized():
            self.expand()
    
    def currentWidget(self):
        """
        Public method to get a reference to the current widget.
        
        @return reference to the current widget (QWidget)
        """
        return self.__stackedWidget.currentWidget()
    
    def setCurrentWidget(self, widget):
        """
        Public slot to set the current widget.
        
        @param widget reference to the widget to become the current widget
            (QWidget)
        """
        self.__stackedWidget.setCurrentWidget(widget)
        self.__tabBar.setCurrentIndex(self.__stackedWidget.currentIndex())
        if self.isMinimized():
            self.expand()
    
    def indexOf(self, widget):
        """
        Public method to get the index of the given widget.
        
        @param widget reference to the widget to get the index of (QWidget)
        @return index of the given widget (integer)
        """
        return self.__stackedWidget.indexOf(widget)
    
    def isTabEnabled(self, index):
        """
        Public method to check, if a tab is enabled.
        
        @param index index of the tab to check (integer)
        @return flag indicating the enabled state (boolean)
        """
        return self.__tabBar.isTabEnabled(index)
    
    def setTabEnabled(self, index, enabled):
        """
        Public method to set the enabled state of a tab.
        
        @param index index of the tab to set (integer)
        @param enabled enabled state to set (boolean)
        """
        self.__tabBar.setTabEnabled(index, enabled)
    
    def orientation(self):
        """
        Public method to get the orientation of the sidebar.
        
        @return orientation of the sidebar (North, East, South, West)
        """
        return self.__orientation
    
    def setOrientation(self, orient):
        """
        Public method to set the orientation of the sidebar.

        @param orient orientation of the sidebar (North, East, South, West)
        """
        if orient == E5SideBar.North:
            self.__tabBar.setShape(QTabBar.RoundedNorth)
            self.__tabBar.setSizePolicy(
                QSizePolicy.Expanding, QSizePolicy.Preferred)
            self.barLayout.setDirection(QBoxLayout.LeftToRight)
            self.layout.setDirection(QBoxLayout.TopToBottom)
            self.layout.setAlignment(self.barLayout, Qt.AlignLeft)
        elif orient == E5SideBar.East:
            self.__tabBar.setShape(QTabBar.RoundedEast)
            self.__tabBar.setSizePolicy(
                QSizePolicy.Preferred, QSizePolicy.Expanding)
            self.barLayout.setDirection(QBoxLayout.TopToBottom)
            self.layout.setDirection(QBoxLayout.RightToLeft)
            self.layout.setAlignment(self.barLayout, Qt.AlignTop)
        elif orient == E5SideBar.South:
            self.__tabBar.setShape(QTabBar.RoundedSouth)
            self.__tabBar.setSizePolicy(
                QSizePolicy.Expanding, QSizePolicy.Preferred)
            self.barLayout.setDirection(QBoxLayout.LeftToRight)
            self.layout.setDirection(QBoxLayout.BottomToTop)
            self.layout.setAlignment(self.barLayout, Qt.AlignLeft)
        elif orient == E5SideBar.West:
            self.__tabBar.setShape(QTabBar.RoundedWest)
            self.__tabBar.setSizePolicy(
                QSizePolicy.Preferred, QSizePolicy.Expanding)
            self.barLayout.setDirection(QBoxLayout.TopToBottom)
            self.layout.setDirection(QBoxLayout.LeftToRight)
            self.layout.setAlignment(self.barLayout, Qt.AlignTop)
        self.__orientation = orient
    
    def tabIcon(self, index):
        """
        Public method to get the icon of a tab.
        
        @param index index of the tab (integer)
        @return icon of the tab (QIcon)
        """
        return self.__tabBar.tabIcon(index)
    
    def setTabIcon(self, index, icon):
        """
        Public method to set the icon of a tab.
        
        @param index index of the tab (integer)
        @param icon icon to be set (QIcon)
        """
        self.__tabBar.setTabIcon(index, icon)
    
    def tabText(self, index):
        """
        Public method to get the text of a tab.
        
        @param index index of the tab (integer)
        @return text of the tab (string)
        """
        return self.__tabBar.tabText(index)
    
    def setTabText(self, index, text):
        """
        Public method to set the text of a tab.
        
        @param index index of the tab (integer)
        @param text text to set (string)
        """
        self.__tabBar.setTabText(index, text)
    
    def tabToolTip(self, index):
        """
        Public method to get the tooltip text of a tab.
        
        @param index index of the tab (integer)
        @return tooltip text of the tab (string)
        """
        return self.__tabBar.tabToolTip(index)
    
    def setTabToolTip(self, index, tip):
        """
        Public method to set the tooltip text of a tab.
        
        @param index index of the tab (integer)
        @param tip tooltip text to set (string)
        """
        self.__tabBar.setTabToolTip(index, tip)
    
    def tabWhatsThis(self, index):
        """
        Public method to get the WhatsThis text of a tab.
        
        @param index index of the tab (integer)
        @return WhatsThis text of the tab (string)
        """
        return self.__tabBar.tabWhatsThis(index)
    
    def setTabWhatsThis(self, index, text):
        """
        Public method to set the WhatsThis text of a tab.
        
        @param index index of the tab (integer)
        @param text WhatsThis text to set (string)
        """
        self.__tabBar.setTabWhatsThis(index, text)
    
    def widget(self, index):
        """
        Public method to get a reference to the widget associated with a tab.
        
        @param index index of the tab (integer)
        @return reference to the widget (QWidget)
        """
        return self.__stackedWidget.widget(index)
    
    def saveState(self):
        """
        Public method to save the state of the sidebar.
        
        @return saved state as a byte array (QByteArray)
        """
        if len(self.splitterSizes) == 0:
            if self.splitter:
                self.splitterSizes = self.splitter.sizes()
            self.__bigSize = self.size()
            if self.__orientation in [E5SideBar.North, E5SideBar.South]:
                self.__minSize = self.minimumSizeHint().height()
                self.__maxSize = self.maximumHeight()
            else:
                self.__minSize = self.minimumSizeHint().width()
                self.__maxSize = self.maximumWidth()
        
        data = QByteArray()
        stream = QDataStream(data, QIODevice.WriteOnly)
        stream.setVersion(QDataStream.Qt_4_6)
        
        stream.writeUInt16(self.Version)
        stream.writeBool(self.__minimized)
        stream << self.__bigSize
        stream.writeUInt16(self.__minSize)
        stream.writeUInt16(self.__maxSize)
        stream.writeUInt16(len(self.splitterSizes))
        for size in self.splitterSizes:
            stream.writeUInt16(size)
        stream.writeBool(self.__autoHide)
        
        return data
    
    def restoreState(self, state):
        """
        Public method to restore the state of the sidebar.
        
        @param state byte array containing the saved state (QByteArray)
        @return flag indicating success (boolean)
        """
        if state.isEmpty():
            return False
        
        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            minSize = self.layout.minimumSize().height()
            maxSize = self.maximumHeight()
        else:
            minSize = self.layout.minimumSize().width()
            maxSize = self.maximumWidth()
        
        data = QByteArray(state)
        stream = QDataStream(data, QIODevice.ReadOnly)
        stream.setVersion(QDataStream.Qt_4_6)
        stream.readUInt16()  # version
        minimized = stream.readBool()
        
        if minimized and not self.__minimized:
            self.shrink()
        
        stream >> self.__bigSize
        self.__minSize = max(stream.readUInt16(), minSize)
        self.__maxSize = max(stream.readUInt16(), maxSize)
        count = stream.readUInt16()
        self.splitterSizes = []
        for i in range(count):
            self.splitterSizes.append(stream.readUInt16())
        
        self.__autoHide = stream.readBool()
        self.__autoHideButton.setChecked(not self.__autoHide)
        
        if not minimized:
            self.expand()
        
        return True
    
    #######################################################################
    ## methods below implement the autohide functionality
    #######################################################################
    
    def __autoHideToggled(self, checked):
        """
        Private slot to handle the toggling of the autohide button.
        
        @param checked flag indicating the checked state of the button
            (boolean)
        """
        self.__autoHide = not checked
        if self.__autoHide:
            self.__autoHideButton.setIcon(
                UI.PixmapCache.getIcon("autoHideOn.png"))
        else:
            self.__autoHideButton.setIcon(
                UI.PixmapCache.getIcon("autoHideOff.png"))
    
    def __appFocusChanged(self, old, now):
        """
        Private slot to handle a change of the focus.
        
        @param old reference to the widget, that lost focus (QWidget or None)
        @param now reference to the widget having the focus (QWidget or None)
        """
        self.__hasFocus = self.isAncestorOf(now)
        if self.__autoHide and not self.__hasFocus and not self.isMinimized():
            self.shrink()
        elif self.__autoHide and self.__hasFocus and self.isMinimized():
            self.expand()
    
    def enterEvent(self, event):
        """
        Protected method to handle the mouse entering this widget.
        
        @param event reference to the event (QEvent)
        """
        if self.__autoHide and self.isMinimized():
            self.expand()
        else:
            self.__cancelDelayTimer()
    
    def leaveEvent(self, event):
        """
        Protected method to handle the mouse leaving this widget.
        
        @param event reference to the event (QEvent)
        """
        if self.__autoHide and not self.__hasFocus and not self.isMinimized():
            self.shrink()
        else:
            self.__cancelDelayTimer()
    
    def shutdown(self):
        """
        Public method to shut down the object.
        
        This method does some preparations so the object can be deleted
        properly. It disconnects from the focusChanged signal in order to
        avoid trouble later on.
        """
        e5App().focusChanged[QWidget, QWidget].disconnect(
            self.__appFocusChanged)
Beispiel #24
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setStyleSheet('''
            background-color: #b3e6ff;
        ''')

        self.setWindowFlags(Qt.FramelessWindowHint)

        self.menu = InitWidget()
        self.gameWindow = GameWindow('', '', gameMode=GameMode.PVP)
        self.currentWidget = DisplayedWidget.MENU
        self.mode = GameMode.PVP

        # self.menu.PvAISignal.connect(self.goToNames)
        # self.menu.PvPSignal.connect(self.goToNames)

        self.menu.PvAISignal.connect(self.goToPVEGame)
        self.menu.PvPSignal.connect(self.goToPVPGame)
        self.menu.showHSTSignal.connect(self.goToScoreTable)

        self.stack = QStackedWidget(self)
        self.stack.addWidget(self.menu)
        self.stack.addWidget(self.gameWindow)
        self.setCentralWidget(self.stack)

        self.setGeometry(0, 0, 800, 600)
        self.setWindowTitle('Морской бой')

        self.mLastMousePosition = None
        self.mMoving = None
        self.gameOverWidget = None
        self.playerNamesWidget = None
        self.AIChooseWidget = None
        self.scoreBoardWidget = None

    def goToNames(self, mode=GameMode.PVE):
        self.playerNamesWidget = PlayerNamesWidget()
        self.playerNamesWidget.prepareWidget(mode)

        if mode == GameMode.PVE:
            self.AIChooseWidget = AIChooseWidget()
            self.playerNamesWidget.startSignal.connect(self.choosePvEMode)
            self.AIChooseWidget.modeSignal.connect(self.goToGameWindow)
        else:
            self.playerNamesWidget.startSignal.connect(self.goToGameWindow1)

        self.playerNamesWidget.menuSignal.connect(self.goToMenu)
        self.stack.addWidget(self.playerNamesWidget)
        self.stack.setCurrentWidget(self.playerNamesWidget)

    @pyqtSlot()
    def goToMenu(self):
        self.currentWidget = DisplayedWidget.MENU
        self.display()

    @pyqtSlot()
    def goToPVPGame(self):
        self.mode = GameMode.PVP
        self.goToNames(GameMode.PVP)

    @pyqtSlot()
    def goToPVEGame(self):
        self.mode = GameMode.PVE
        self.goToNames(GameMode.PVE)

    @pyqtSlot()
    def choosePvEMode(self):
        self.stack.addWidget(self.AIChooseWidget)
        self.stack.setCurrentWidget(self.AIChooseWidget)
        self.AIChooseWidget.backSignal.connect(self.goToNames)

    @pyqtSlot(str, str)
    def goToGameWindow1(self, player_1, player_2):
        self.currentWidget = DisplayedWidget.GAME
        self.gameWindow = GameWindow(player_1, player_2, self.mode)
        self.gameWindow.gameOverSignal.connect(self.showGameOver)
        self.gameWindow.toMenuSignal.connect(self.goToMenu)
        self.stack.insertWidget(DisplayedWidget.GAME, self.gameWindow)

        self.display()

    @pyqtSlot(GameLevel)
    def goToGameWindow(self, mode):
        self.currentWidget = DisplayedWidget.GAME
        player_1 = self.playerNamesWidget.getPlayer1()
        self.gameWindow = GameWindow(player_1, "OpenAI", GameMode.PVE, mode)
        self.gameWindow.gameOverSignal.connect(self.showGameOver)
        self.gameWindow.toMenuSignal.connect(self.goToMenu)
        self.stack.insertWidget(DisplayedWidget.GAME, self.gameWindow)

        self.display()

    # def goToGameWindow_(self, gameMode):
    #     self.currentWidget = DisplayedWidget.GAME
    #     self.gameWindow = GameWindow(gameMode=gameMode)
    #     self.gameWindow.gameOverSignal.connect(self.showGameOver)
    #     self.gameWindow.toMenuSignal.connect(self.goToMenu)
    #     self.stack.insertWidget(DisplayedWidget.GAME, self.gameWindow)
    #
    #     self.display()

    @pyqtSlot(str)
    def showGameOver(self, player):
        self.gameOverWidget = GameOverWidget(player)
        self.gameOverWidget.ui.menuButton.clicked.connect(self.goToMenu)
        self.stack.addWidget(self.gameOverWidget)
        self.stack.setCurrentWidget(self.gameOverWidget)

    @pyqtSlot()
    def goToScoreTable(self):
        self.stack.removeWidget(self.scoreBoardWidget)
        self.scoreBoardWidget = ScoreBoardWidget()
        self.scoreBoardWidget.onExit.connect(self.goToMenu)
        self.stack.addWidget(self.scoreBoardWidget)
        self.stack.setCurrentWidget(self.scoreBoardWidget)

    def display(self):
        self.stack.setCurrentIndex(self.currentWidget)

    def quit(self):
        QCoreApplication.quit()

    def mousePressEvent(self, event: QtGui.QMouseEvent) -> None:
        if event.button() == Qt.MouseButton.LeftButton:
            self.mMoving = True
            self.mLastMousePosition = event.pos()

    def mouseMoveEvent(self, event: QtGui.QMouseEvent) -> None:
        if self.mMoving:
            self.move(self.pos() + event.pos() - self.mLastMousePosition)

    def mouseReleaseEvent(self, event: QtGui.QMouseEvent) -> None:
        if event.button() == Qt.MouseButton.LeftButton:
            self.mMoving = False
Beispiel #25
0
class PyMultiPageWidget(QWidget):

    currentIndexChanged = pyqtSignal(int)

    pageTitleChanged = pyqtSignal(str)

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

        self.comboBox = QComboBox()
        # MAGIC
        # It is important that the combo box has an object name beginning
        # with '__qt__passive_', otherwise, it is inactive in the form editor
        # of the designer and you can't change the current page via the
        # combo box.
        # MAGIC
        self.comboBox.setObjectName('__qt__passive_comboBox')
        self.stackWidget = QStackedWidget()
        self.comboBox.activated.connect(self.setCurrentIndex)
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.comboBox)
        self.layout.addWidget(self.stackWidget)
        self.setLayout(self.layout)

    def sizeHint(self):
        return QSize(200, 150)

    def count(self):
        return self.stackWidget.count()

    def widget(self, index):
        return self.stackWidget.widget(index)

    @pyqtSlot(QWidget)
    def addPage(self, page):
        self.insertPage(self.count(), page)

    @pyqtSlot(int, QWidget)
    def insertPage(self, index, page):
        page.setParent(self.stackWidget)
        self.stackWidget.insertWidget(index, page)
        title = page.windowTitle()
        if title == "":
            title = "Page %d" % (self.comboBox.count() + 1)
            page.setWindowTitle(title)
        self.comboBox.insertItem(index, title)

    @pyqtSlot(int)
    def removePage(self, index):
        widget = self.stackWidget.widget(index)
        self.stackWidget.removeWidget(widget)
        self.comboBox.removeItem(index)

    def getPageTitle(self):
        return self.stackWidget.currentWidget().windowTitle()

    @pyqtSlot(str)
    def setPageTitle(self, newTitle):
        self.comboBox.setItemText(self.getCurrentIndex(), newTitle)
        self.stackWidget.currentWidget().setWindowTitle(newTitle)
        self.pageTitleChanged.emit(newTitle)

    def getCurrentIndex(self):
        return self.stackWidget.currentIndex()

    @pyqtSlot(int)
    def setCurrentIndex(self, index):
        if index != self.getCurrentIndex():
            self.stackWidget.setCurrentIndex(index)
            self.comboBox.setCurrentIndex(index)
            self.currentIndexChanged.emit(index)

    pageTitle = pyqtProperty(str,
                             fget=getPageTitle,
                             fset=setPageTitle,
                             stored=False)
    currentIndex = pyqtProperty(int,
                                fget=getCurrentIndex,
                                fset=setCurrentIndex)
Beispiel #26
0
class MainWindow(QMainWindow):
    def __init__(self, resolution: QRect, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.setWindowTitle("")
        self.screens_config = []
        self.current_screen = 0
        self.sub_screens = {}
        self.button = {}
        self.subscreen_stacked_widget = QStackedWidget()
        self.number_of_subs = 0
        self.main_stack_widget = QStackedWidget()
        self.main_widget = QWidget()
        self.main_layout = QGridLayout()
        self.gui_element_builder = GuiElementsBuilder()
        self.gui_button_builder = GuiButtonBuilder()
        self.gui_subscreen_builder = GuiSubscreenBuilder()
        self.resolution = resolution
        self.alarm_observer = AlarmObserver(self)
        self.alarm_widget = Alarm(self.alarm_observer, "Alarm_Widget",
                                  "#550055", self)

    def set_current_subscreen(self):
        source_button = self.sender()
        for i in range(0, self.number_of_subs):
            # print(source_button.text(), self.subscreen_stacked_widget.widget(i).get_name())
            if self.subscreen_stacked_widget.widget(
                    i).get_name() == source_button.text():
                self.subscreen_stacked_widget.setCurrentIndex(i)

    def toggle_main_widget(self, index: int):
        max_value = self.main_stack_widget.count()
        self.main_stack_widget.setCurrentIndex(index % max_value)

    def close_main_window(self):
        self.close()

    def update_from_subscreen(self, msg: dict) -> None:
        print(msg)
        self.alarm_widget.set_alarm_text(msg)
        self.toggle_main_widget(1)

    def init_with_config(self, config: dict):
        self.screens_config = config

        # Set Title
        title = str(config['main']['name'])
        self.setWindowTitle(title)
        # Set window flag
        flags = Qt.CustomizeWindowHint  # Small Frame
        # flags = Qt.FramelessWindowHint # No Frame
        self.setWindowFlags(flags)

        # Set Resolution ######################################################
        # via config
        window_width = config['main']["resolution"][0]
        window_height = config['main']["resolution"][1]
        # via given screen geometry
        # window_width = self.resolution.width()
        # window_height = self.resolution.height()
        # Set Resolution End ##################################################

        button_width = config['main']["button-size"][0]
        button_height = config['main']["button-size"][1]

        front_color = config['main']["front_color"]
        background_color = config['main']["background_color"]
        font = config['main']["font"]

        self.number_of_subs = len(config['sub'])
        self.gui_element_builder.set_font(font)

        self.setFixedSize(window_width, window_height)

        self.main_widget.setLayout(self.main_layout)
        self.main_widget.setStyleSheet("background-color:" + background_color)
        vbox_menu = QVBoxLayout()
        vbox_menu.setSizeConstraint(QLayout.SetFixedSize)

        vbox_menu.addWidget(
            self.gui_element_builder.get_svg_widget(Gui_Element.TOP_LEFT_SHORT,
                                                    100, 191, front_color))
        button_list_widget = QListWidget()
        vbox_menu.addWidget(button_list_widget)
        vbox_menu.addWidget(
            self.gui_element_builder.get_svg_widget(
                Gui_Element.BOTTOM_LEFT_SHORT, 100, 191, front_color))

        # Header #################################################################
        self.main_layout.addWidget(
            self.gui_element_builder.get_svg_widget(Gui_Element.BUTTON, 33,
                                                    712, front_color), 0, 1, 1,
            1, Qt.AlignTop)
        self.main_layout.addWidget(
            self.gui_element_builder.get_svg_widget(Gui_Element.BUTTON, 33, 52,
                                                    front_color), 0, 3,
            Qt.AlignTop)
        self.main_layout.addWidget(
            self.gui_element_builder.get_svg_widget(Gui_Element.END_RIGHT, 33,
                                                    33, front_color), 0, 4,
            Qt.AlignTop)
        # Header - END ###########################################################

        # Menu
        self.main_layout.addLayout(vbox_menu, 0, 0, 4, 1)
        # Central Window
        self.main_layout.addWidget(self.subscreen_stacked_widget, 1, 1, 2, 4)
        # Footer #################################################################
        self.main_layout.addWidget(
            self.gui_element_builder.get_svg_widget(Gui_Element.BUTTON, 33,
                                                    712, front_color), 3, 1,
            Qt.AlignBottom)
        # Add Exit Button
        exit_button = QPushButton("EXIT")
        exit_button.setFont(QFont(font, 20, QFont.Bold))
        exit_button.setFixedSize(52, 33)
        exit_button.setStyleSheet("background:#ff0000; border:1px solid " +
                                  front_color + ";")
        exit_button.clicked.connect(lambda state: self.close())

        self.main_layout.addWidget(exit_button, 3, 3, Qt.AlignBottom)
        self.main_layout.addWidget(
            self.gui_element_builder.get_svg_widget(Gui_Element.END_RIGHT, 33,
                                                    33, front_color, font), 3,
            4, Qt.AlignBottom)
        # Footer - END ###########################################################

        # button_ListWidget.setVerticalScrolllayout(QAbstractItemView.ScrollMode.ScrollPerItem)
        button_list_widget.setStyleSheet("QListWidget{background:" +
                                         background_color +
                                         ";  border: 0px solid " +
                                         front_color + ";}")

        # Erstellen der linken Button-Leiste ##############
        button_width = button_width * window_width / 100
        button_height = button_height * window_height / 100
        button_size = QSize(button_width, button_height)
        for i in range(0, self.number_of_subs):
            sub_button_list_item = QListWidgetItem(button_list_widget)
            placeholder_list_item = QListWidgetItem(button_list_widget)
            placeholder_list_item.setSizeHint(QSize(button_width, 4))
            placeholder_list_item.setBackground(QColor(background_color))

            flag = placeholder_list_item.flags() & Qt.ItemIsUserCheckable
            placeholder_list_item.setFlags(flag)
            # Widgets ##################################################################################################
            self.subscreen_stacked_widget.insertWidget(
                i,
                self.gui_subscreen_builder.init_with_config(
                    self.screens_config['sub'][i], self.alarm_observer))

            # Buttons ##################################################################################################
            self.gui_button_builder.set_color(
                self.screens_config['sub'][i]["Background"])
            self.gui_button_builder.set_size(button_height, button_width)
            self.button[i] = self.gui_button_builder.create_button(
                self.screens_config["sub"][i]["name"], Gui_Element.BUTTON_TEXT)

            sub_button_list_item.setSizeHint(button_size)
            button_list_widget.addItem(placeholder_list_item)
            button_list_widget.addItem(sub_button_list_item)
            button_list_widget.setItemWidget(sub_button_list_item,
                                             self.button[i])
            # signals ##################################################################################################
            self.button[i].clicked.connect(
                lambda widget=self.subscreen_stacked_widget.widget(
                    i): self.set_current_subscreen())

        # button_list_widget.setMaximumWidth(1000)
        button_list_widget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        button_list_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        button_list_widget.setMaximumWidth(
            button_list_widget.sizeHintForColumn(0))

        #############################################
        self.subscreen_stacked_widget.setCurrentIndex(0)
        self.main_stack_widget.insertWidget(0, self.main_widget)
        self.main_stack_widget.insertWidget(1, self.alarm_widget)
        self.main_stack_widget.setCurrentIndex(0)
        self.setCentralWidget(self.main_stack_widget)
Beispiel #27
0
class PyMultiPageWidget(QWidget):

    currentIndexChanged = pyqtSignal(int)

    pageTitleChanged = pyqtSignal(str)

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

        self.comboBox = QComboBox()
        # MAGIC
        # It is important that the combo box has an object name beginning
        # with '__qt__passive_', otherwise, it is inactive in the form editor
        # of the designer and you can't change the current page via the
        # combo box.
        # MAGIC
        self.comboBox.setObjectName('__qt__passive_comboBox')        
        self.stackWidget = QStackedWidget()
        self.comboBox.activated.connect(self.setCurrentIndex)
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.comboBox)
        self.layout.addWidget(self.stackWidget)
        self.setLayout(self.layout)

    def sizeHint(self):
        return QSize(200, 150)

    def count(self):
        return self.stackWidget.count()

    def widget(self, index):
        return self.stackWidget.widget(index)

    @pyqtSlot(QWidget)
    def addPage(self, page):
        self.insertPage(self.count(), page)

    @pyqtSlot(int, QWidget)
    def insertPage(self, index, page):
        page.setParent(self.stackWidget)
        self.stackWidget.insertWidget(index, page)
        title = page.windowTitle()
        if title == "":
            title = "Page %d" % (self.comboBox.count() + 1)
            page.setWindowTitle(title)
        self.comboBox.insertItem(index, title)

    @pyqtSlot(int)
    def removePage(self, index):
        widget = self.stackWidget.widget(index)
        self.stackWidget.removeWidget(widget)
        self.comboBox.removeItem(index)

    def getPageTitle(self):
        return self.stackWidget.currentWidget().windowTitle()
    
    @pyqtSlot(str)
    def setPageTitle(self, newTitle):
        self.comboBox.setItemText(self.getCurrentIndex(), newTitle)
        self.stackWidget.currentWidget().setWindowTitle(newTitle)
        self.pageTitleChanged.emit(newTitle)

    def getCurrentIndex(self):
        return self.stackWidget.currentIndex()

    @pyqtSlot(int)
    def setCurrentIndex(self, index):
        if index != self.getCurrentIndex():
            self.stackWidget.setCurrentIndex(index)
            self.comboBox.setCurrentIndex(index)
            self.currentIndexChanged.emit(index)

    pageTitle = pyqtProperty(str, fget=getPageTitle, fset=setPageTitle, stored=False)
    currentIndex = pyqtProperty(int, fget=getCurrentIndex, fset=setCurrentIndex)
Beispiel #28
0
class PyMultiPageWidget(QWidget):
    currentIndexChanged = pyqtSignal(int)
    pageTitleChanged = pyqtSignal(str)

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

        self.comboBox = QComboBox()
        self.comboBox.setObjectName('__qt__passive_comboBox')
        self.stackWidget = QStackedWidget()
        self.comboBox.activated.connect(self.setCurrentIndex)
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.comboBox)
        self.layout.addWidget(self.stackWidget)
        self.setLayout(self.layout)

    def sizeHint(self):
        return QSize(200, 150)

    def count(self):
        return self.stackWidget.count()

    def widget(self, index):
        return self.stackWidget.widget(index)

    @pyqtSlot(QWidget)
    def addPage(self, page):
        self.insertPage(self.count(), page)

    @pyqtSlot(int, QWidget)
    def insertPage(self, index, page):
        page.setParent(self.stackWidget)
        self.stackWidget.insertWidget(index, page)
        title = page.windowTitle()
        if title == "":
            title = "Page %d" % (self.comboBox.count() + 1)
            page.setWindowTitle(title)
        self.comboBox.insertItem(index, title)

    @pyqtSlot(int)
    def removePage(self, index):
        widget = self.stackWidget.widget(index)
        self.stackWidget.removeWidget(widget)
        self.comboBox.removeItem(index)

    def getPageTitle(self):
        cw = self.stackWidget.currentWidget()
        return cw.windowTitle() if cw is not None else ''

    @pyqtSlot(str)
    def setPageTitle(self, newTitle):
        cw = self.stackWidget.currentWidget()
        if cw is not None:
            self.comboBox.setItemText(self.getCurrentIndex(), newTitle)
            cw.setWindowTitle(newTitle)
            self.pageTitleChanged.emit(newTitle)

    def getCurrentIndex(self):
        return self.stackWidget.currentIndex()

    @pyqtSlot(int)
    def setCurrentIndex(self, index):
        if index != self.getCurrentIndex():
            self.stackWidget.setCurrentIndex(index)
            self.comboBox.setCurrentIndex(index)
            self.currentIndexChanged.emit(index)

    pageTitle = pyqtProperty(str, fget=getPageTitle, fset=setPageTitle, stored=False)
    currentIndex = pyqtProperty(int, fget=getCurrentIndex, fset=setCurrentIndex)
Beispiel #29
0
class E5SideBar(QWidget):
    """
    Class implementing a sidebar with a widget area, that is hidden or shown,
    if the current tab is clicked again.
    """
    Version = 1

    North = 0
    East = 1
    South = 2
    West = 3

    def __init__(self, orientation=None, delay=200, parent=None):
        """
        Constructor
        
        @param orientation orientation of the sidebar widget (North, East,
            South, West)
        @param delay value for the expand/shrink delay in milliseconds
            (integer)
        @param parent parent widget (QWidget)
        """
        super(E5SideBar, self).__init__(parent)

        self.__tabBar = QTabBar()
        self.__tabBar.setDrawBase(True)
        self.__tabBar.setShape(QTabBar.RoundedNorth)
        self.__tabBar.setUsesScrollButtons(True)
        self.__tabBar.setDrawBase(False)
        self.__stackedWidget = QStackedWidget(self)
        self.__stackedWidget.setContentsMargins(0, 0, 0, 0)
        self.__autoHideButton = QToolButton()
        self.__autoHideButton.setCheckable(True)
        self.__autoHideButton.setIcon(
            UI.PixmapCache.getIcon("autoHideOff.png"))
        self.__autoHideButton.setChecked(True)
        self.__autoHideButton.setToolTip(
            self.tr("Deselect to activate automatic collapsing"))
        self.barLayout = QBoxLayout(QBoxLayout.LeftToRight)
        self.barLayout.setContentsMargins(0, 0, 0, 0)
        self.layout = QBoxLayout(QBoxLayout.TopToBottom)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(0)
        self.barLayout.addWidget(self.__autoHideButton)
        self.barLayout.addWidget(self.__tabBar)
        self.layout.addLayout(self.barLayout)
        self.layout.addWidget(self.__stackedWidget)
        self.setLayout(self.layout)

        # initialize the delay timer
        self.__actionMethod = None
        self.__delayTimer = QTimer(self)
        self.__delayTimer.setSingleShot(True)
        self.__delayTimer.setInterval(delay)
        self.__delayTimer.timeout.connect(self.__delayedAction)

        self.__minimized = False
        self.__minSize = 0
        self.__maxSize = 0
        self.__bigSize = QSize()

        self.splitter = None
        self.splitterSizes = []

        self.__hasFocus = False
        # flag storing if this widget or any child has the focus
        self.__autoHide = False

        self.__tabBar.installEventFilter(self)

        self.__orientation = E5SideBar.North
        if orientation is None:
            orientation = E5SideBar.North
        self.setOrientation(orientation)

        self.__tabBar.currentChanged[int].connect(
            self.__stackedWidget.setCurrentIndex)
        e5App().focusChanged.connect(self.__appFocusChanged)
        self.__autoHideButton.toggled[bool].connect(self.__autoHideToggled)

    def setSplitter(self, splitter):
        """
        Public method to set the splitter managing the sidebar.
        
        @param splitter reference to the splitter (QSplitter)
        """
        self.splitter = splitter
        self.splitter.splitterMoved.connect(self.__splitterMoved)
        self.splitter.setChildrenCollapsible(False)
        index = self.splitter.indexOf(self)
        self.splitter.setCollapsible(index, False)

    def __splitterMoved(self, pos, index):
        """
        Private slot to react on splitter moves.
        
        @param pos new position of the splitter handle (integer)
        @param index index of the splitter handle (integer)
        """
        if self.splitter:
            self.splitterSizes = self.splitter.sizes()

    def __delayedAction(self):
        """
        Private slot to handle the firing of the delay timer.
        """
        if self.__actionMethod is not None:
            self.__actionMethod()

    def setDelay(self, delay):
        """
        Public method to set the delay value for the expand/shrink delay in
        milliseconds.
        
        @param delay value for the expand/shrink delay in milliseconds
            (integer)
        """
        self.__delayTimer.setInterval(delay)

    def delay(self):
        """
        Public method to get the delay value for the expand/shrink delay in
        milliseconds.
        
        @return value for the expand/shrink delay in milliseconds (integer)
        """
        return self.__delayTimer.interval()

    def __cancelDelayTimer(self):
        """
        Private method to cancel the current delay timer.
        """
        self.__delayTimer.stop()
        self.__actionMethod = None

    def shrink(self):
        """
        Public method to record a shrink request.
        """
        self.__delayTimer.stop()
        self.__actionMethod = self.__shrinkIt
        self.__delayTimer.start()

    def __shrinkIt(self):
        """
        Private method to shrink the sidebar.
        """
        self.__minimized = True
        self.__bigSize = self.size()
        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            self.__minSize = self.minimumSizeHint().height()
            self.__maxSize = self.maximumHeight()
        else:
            self.__minSize = self.minimumSizeHint().width()
            self.__maxSize = self.maximumWidth()
        if self.splitter:
            self.splitterSizes = self.splitter.sizes()

        self.__stackedWidget.hide()

        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            self.setFixedHeight(self.__tabBar.minimumSizeHint().height())
        else:
            self.setFixedWidth(self.__tabBar.minimumSizeHint().width())

        self.__actionMethod = None

    def expand(self):
        """
        Public method to record a expand request.
        """
        self.__delayTimer.stop()
        self.__actionMethod = self.__expandIt
        self.__delayTimer.start()

    def __expandIt(self):
        """
        Private method to expand the sidebar.
        """
        self.__minimized = False
        self.__stackedWidget.show()
        self.resize(self.__bigSize)
        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            minSize = max(self.__minSize, self.minimumSizeHint().height())
            self.setMinimumHeight(minSize)
            self.setMaximumHeight(self.__maxSize)
        else:
            minSize = max(self.__minSize, self.minimumSizeHint().width())
            self.setMinimumWidth(minSize)
            self.setMaximumWidth(self.__maxSize)
        if self.splitter:
            self.splitter.setSizes(self.splitterSizes)

        self.__actionMethod = None

    def isMinimized(self):
        """
        Public method to check the minimized state.
        
        @return flag indicating the minimized state (boolean)
        """
        return self.__minimized

    def isAutoHiding(self):
        """
        Public method to check, if the auto hide function is active.
        
        @return flag indicating the state of auto hiding (boolean)
        """
        return self.__autoHide

    def eventFilter(self, obj, evt):
        """
        Public method to handle some events for the tabbar.
        
        @param obj reference to the object (QObject)
        @param evt reference to the event object (QEvent)
        @return flag indicating, if the event was handled (boolean)
        """
        if obj == self.__tabBar:
            if evt.type() == QEvent.MouseButtonPress:
                pos = evt.pos()
                for i in range(self.__tabBar.count()):
                    if self.__tabBar.tabRect(i).contains(pos):
                        break

                if i == self.__tabBar.currentIndex():
                    if self.isMinimized():
                        self.expand()
                    else:
                        self.shrink()
                    return True
                elif self.isMinimized():
                    self.expand()
            elif evt.type() == QEvent.Wheel:
                if qVersion() >= "5.0.0":
                    delta = evt.angleDelta().y()
                else:
                    delta = evt.delta()
                if delta > 0:
                    self.prevTab()
                else:
                    self.nextTab()
                return True

        return QWidget.eventFilter(self, obj, evt)

    def addTab(self, widget, iconOrLabel, label=None):
        """
        Public method to add a tab to the sidebar.
        
        @param widget reference to the widget to add (QWidget)
        @param iconOrLabel reference to the icon or the label text of the tab
            (QIcon, string)
        @param label the labeltext of the tab (string) (only to be
            used, if the second parameter is a QIcon)
        """
        if label:
            index = self.__tabBar.addTab(iconOrLabel, label)
            self.__tabBar.setTabToolTip(index, label)
        else:
            index = self.__tabBar.addTab(iconOrLabel)
            self.__tabBar.setTabToolTip(index, iconOrLabel)
        self.__stackedWidget.addWidget(widget)
        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            self.__minSize = self.minimumSizeHint().height()
        else:
            self.__minSize = self.minimumSizeHint().width()

    def insertTab(self, index, widget, iconOrLabel, label=None):
        """
        Public method to insert a tab into the sidebar.
        
        @param index the index to insert the tab at (integer)
        @param widget reference to the widget to insert (QWidget)
        @param iconOrLabel reference to the icon or the labeltext of the tab
            (QIcon, string)
        @param label the labeltext of the tab (string) (only to be
            used, if the second parameter is a QIcon)
        """
        if label:
            index = self.__tabBar.insertTab(index, iconOrLabel, label)
            self.__tabBar.setTabToolTip(index, label)
        else:
            index = self.__tabBar.insertTab(index, iconOrLabel)
            self.__tabBar.setTabToolTip(index, iconOrLabel)
        self.__stackedWidget.insertWidget(index, widget)
        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            self.__minSize = self.minimumSizeHint().height()
        else:
            self.__minSize = self.minimumSizeHint().width()

    def removeTab(self, index):
        """
        Public method to remove a tab.
        
        @param index the index of the tab to remove (integer)
        """
        self.__stackedWidget.removeWidget(self.__stackedWidget.widget(index))
        self.__tabBar.removeTab(index)
        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            self.__minSize = self.minimumSizeHint().height()
        else:
            self.__minSize = self.minimumSizeHint().width()

    def clear(self):
        """
        Public method to remove all tabs.
        """
        while self.count() > 0:
            self.removeTab(0)

    def prevTab(self):
        """
        Public slot used to show the previous tab.
        """
        ind = self.currentIndex() - 1
        if ind == -1:
            ind = self.count() - 1

        self.setCurrentIndex(ind)
        self.currentWidget().setFocus()

    def nextTab(self):
        """
        Public slot used to show the next tab.
        """
        ind = self.currentIndex() + 1
        if ind == self.count():
            ind = 0

        self.setCurrentIndex(ind)
        self.currentWidget().setFocus()

    def count(self):
        """
        Public method to get the number of tabs.
        
        @return number of tabs in the sidebar (integer)
        """
        return self.__tabBar.count()

    def currentIndex(self):
        """
        Public method to get the index of the current tab.
        
        @return index of the current tab (integer)
        """
        return self.__stackedWidget.currentIndex()

    def setCurrentIndex(self, index):
        """
        Public slot to set the current index.
        
        @param index the index to set as the current index (integer)
        """
        self.__tabBar.setCurrentIndex(index)
        self.__stackedWidget.setCurrentIndex(index)
        if self.isMinimized():
            self.expand()

    def currentWidget(self):
        """
        Public method to get a reference to the current widget.
        
        @return reference to the current widget (QWidget)
        """
        return self.__stackedWidget.currentWidget()

    def setCurrentWidget(self, widget):
        """
        Public slot to set the current widget.
        
        @param widget reference to the widget to become the current widget
            (QWidget)
        """
        self.__stackedWidget.setCurrentWidget(widget)
        self.__tabBar.setCurrentIndex(self.__stackedWidget.currentIndex())
        if self.isMinimized():
            self.expand()

    def indexOf(self, widget):
        """
        Public method to get the index of the given widget.
        
        @param widget reference to the widget to get the index of (QWidget)
        @return index of the given widget (integer)
        """
        return self.__stackedWidget.indexOf(widget)

    def isTabEnabled(self, index):
        """
        Public method to check, if a tab is enabled.
        
        @param index index of the tab to check (integer)
        @return flag indicating the enabled state (boolean)
        """
        return self.__tabBar.isTabEnabled(index)

    def setTabEnabled(self, index, enabled):
        """
        Public method to set the enabled state of a tab.
        
        @param index index of the tab to set (integer)
        @param enabled enabled state to set (boolean)
        """
        self.__tabBar.setTabEnabled(index, enabled)

    def orientation(self):
        """
        Public method to get the orientation of the sidebar.
        
        @return orientation of the sidebar (North, East, South, West)
        """
        return self.__orientation

    def setOrientation(self, orient):
        """
        Public method to set the orientation of the sidebar.

        @param orient orientation of the sidebar (North, East, South, West)
        """
        if orient == E5SideBar.North:
            self.__tabBar.setShape(QTabBar.RoundedNorth)
            self.__tabBar.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Preferred)
            self.barLayout.setDirection(QBoxLayout.LeftToRight)
            self.layout.setDirection(QBoxLayout.TopToBottom)
            self.layout.setAlignment(self.barLayout, Qt.AlignLeft)
        elif orient == E5SideBar.East:
            self.__tabBar.setShape(QTabBar.RoundedEast)
            self.__tabBar.setSizePolicy(QSizePolicy.Preferred,
                                        QSizePolicy.Expanding)
            self.barLayout.setDirection(QBoxLayout.TopToBottom)
            self.layout.setDirection(QBoxLayout.RightToLeft)
            self.layout.setAlignment(self.barLayout, Qt.AlignTop)
        elif orient == E5SideBar.South:
            self.__tabBar.setShape(QTabBar.RoundedSouth)
            self.__tabBar.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Preferred)
            self.barLayout.setDirection(QBoxLayout.LeftToRight)
            self.layout.setDirection(QBoxLayout.BottomToTop)
            self.layout.setAlignment(self.barLayout, Qt.AlignLeft)
        elif orient == E5SideBar.West:
            self.__tabBar.setShape(QTabBar.RoundedWest)
            self.__tabBar.setSizePolicy(QSizePolicy.Preferred,
                                        QSizePolicy.Expanding)
            self.barLayout.setDirection(QBoxLayout.TopToBottom)
            self.layout.setDirection(QBoxLayout.LeftToRight)
            self.layout.setAlignment(self.barLayout, Qt.AlignTop)
        self.__orientation = orient

    def tabIcon(self, index):
        """
        Public method to get the icon of a tab.
        
        @param index index of the tab (integer)
        @return icon of the tab (QIcon)
        """
        return self.__tabBar.tabIcon(index)

    def setTabIcon(self, index, icon):
        """
        Public method to set the icon of a tab.
        
        @param index index of the tab (integer)
        @param icon icon to be set (QIcon)
        """
        self.__tabBar.setTabIcon(index, icon)

    def tabText(self, index):
        """
        Public method to get the text of a tab.
        
        @param index index of the tab (integer)
        @return text of the tab (string)
        """
        return self.__tabBar.tabText(index)

    def setTabText(self, index, text):
        """
        Public method to set the text of a tab.
        
        @param index index of the tab (integer)
        @param text text to set (string)
        """
        self.__tabBar.setTabText(index, text)

    def tabToolTip(self, index):
        """
        Public method to get the tooltip text of a tab.
        
        @param index index of the tab (integer)
        @return tooltip text of the tab (string)
        """
        return self.__tabBar.tabToolTip(index)

    def setTabToolTip(self, index, tip):
        """
        Public method to set the tooltip text of a tab.
        
        @param index index of the tab (integer)
        @param tip tooltip text to set (string)
        """
        self.__tabBar.setTabToolTip(index, tip)

    def tabWhatsThis(self, index):
        """
        Public method to get the WhatsThis text of a tab.
        
        @param index index of the tab (integer)
        @return WhatsThis text of the tab (string)
        """
        return self.__tabBar.tabWhatsThis(index)

    def setTabWhatsThis(self, index, text):
        """
        Public method to set the WhatsThis text of a tab.
        
        @param index index of the tab (integer)
        @param text WhatsThis text to set (string)
        """
        self.__tabBar.setTabWhatsThis(index, text)

    def widget(self, index):
        """
        Public method to get a reference to the widget associated with a tab.
        
        @param index index of the tab (integer)
        @return reference to the widget (QWidget)
        """
        return self.__stackedWidget.widget(index)

    def saveState(self):
        """
        Public method to save the state of the sidebar.
        
        @return saved state as a byte array (QByteArray)
        """
        if len(self.splitterSizes) == 0:
            if self.splitter:
                self.splitterSizes = self.splitter.sizes()
            self.__bigSize = self.size()
            if self.__orientation in [E5SideBar.North, E5SideBar.South]:
                self.__minSize = self.minimumSizeHint().height()
                self.__maxSize = self.maximumHeight()
            else:
                self.__minSize = self.minimumSizeHint().width()
                self.__maxSize = self.maximumWidth()

        data = QByteArray()
        stream = QDataStream(data, QIODevice.WriteOnly)
        stream.setVersion(QDataStream.Qt_4_6)

        stream.writeUInt16(self.Version)
        stream.writeBool(self.__minimized)
        stream << self.__bigSize
        stream.writeUInt16(self.__minSize)
        stream.writeUInt16(self.__maxSize)
        stream.writeUInt16(len(self.splitterSizes))
        for size in self.splitterSizes:
            stream.writeUInt16(size)
        stream.writeBool(self.__autoHide)

        return data

    def restoreState(self, state):
        """
        Public method to restore the state of the sidebar.
        
        @param state byte array containing the saved state (QByteArray)
        @return flag indicating success (boolean)
        """
        if state.isEmpty():
            return False

        if self.__orientation in [E5SideBar.North, E5SideBar.South]:
            minSize = self.layout.minimumSize().height()
            maxSize = self.maximumHeight()
        else:
            minSize = self.layout.minimumSize().width()
            maxSize = self.maximumWidth()

        data = QByteArray(state)
        stream = QDataStream(data, QIODevice.ReadOnly)
        stream.setVersion(QDataStream.Qt_4_6)
        stream.readUInt16()  # version
        minimized = stream.readBool()

        if minimized and not self.__minimized:
            self.shrink()

        stream >> self.__bigSize
        self.__minSize = max(stream.readUInt16(), minSize)
        self.__maxSize = max(stream.readUInt16(), maxSize)
        count = stream.readUInt16()
        self.splitterSizes = []
        for i in range(count):
            self.splitterSizes.append(stream.readUInt16())

        self.__autoHide = stream.readBool()
        self.__autoHideButton.setChecked(not self.__autoHide)

        if not minimized:
            self.expand()

        return True

    #######################################################################
    ## methods below implement the autohide functionality
    #######################################################################

    def __autoHideToggled(self, checked):
        """
        Private slot to handle the toggling of the autohide button.
        
        @param checked flag indicating the checked state of the button
            (boolean)
        """
        self.__autoHide = not checked
        if self.__autoHide:
            self.__autoHideButton.setIcon(
                UI.PixmapCache.getIcon("autoHideOn.png"))
        else:
            self.__autoHideButton.setIcon(
                UI.PixmapCache.getIcon("autoHideOff.png"))

    def __appFocusChanged(self, old, now):
        """
        Private slot to handle a change of the focus.
        
        @param old reference to the widget, that lost focus (QWidget or None)
        @param now reference to the widget having the focus (QWidget or None)
        """
        self.__hasFocus = self.isAncestorOf(now)
        if self.__autoHide and not self.__hasFocus and not self.isMinimized():
            self.shrink()
        elif self.__autoHide and self.__hasFocus and self.isMinimized():
            self.expand()

    def enterEvent(self, event):
        """
        Protected method to handle the mouse entering this widget.
        
        @param event reference to the event (QEvent)
        """
        if self.__autoHide and self.isMinimized():
            self.expand()
        else:
            self.__cancelDelayTimer()

    def leaveEvent(self, event):
        """
        Protected method to handle the mouse leaving this widget.
        
        @param event reference to the event (QEvent)
        """
        if self.__autoHide and not self.__hasFocus and not self.isMinimized():
            self.shrink()
        else:
            self.__cancelDelayTimer()

    def shutdown(self):
        """
        Public method to shut down the object.
        
        This method does some preparations so the object can be deleted
        properly. It disconnects from the focusChanged signal in order to
        avoid trouble later on.
        """
        e5App().focusChanged.disconnect(self.__appFocusChanged)
Beispiel #30
0
class CentralWidget(QWidget):
    # This signals is used by notificator
    databaseSaved = pyqtSignal('QString')
    querySaved = pyqtSignal('QString')

    def __init__(self):
        QWidget.__init__(self)
        box = QVBoxLayout(self)
        box.setContentsMargins(0, 0, 0, 0)
        box.setSpacing(0)

        self.stacked = QStackedWidget()
        box.addWidget(self.stacked)

        self.created = False
        self.__last_open_folder = None
        self.__recent_dbs = []
        if PSetting.RECENT_DBS:
            self.__recent_dbs = PSetting.RECENT_DBS

        Pireal.load_service("central", self)

    @property
    def recent_databases(self):
        return self.__recent_dbs

    @recent_databases.setter
    def recent_databases(self, database_file):
        if database_file in PSetting.RECENT_DBS:
            PSetting.RECENT_DBS.remove(database_file)
        PSetting.RECENT_DBS.insert(0, database_file)
        self.__recent_dbs = PSetting.RECENT_DBS

    def create_database(self):
        """ Show a wizard widget to create a new database,
        only have one database open at time.
        """

        if self.created:
            QMessageBox.information(self,
                                    self.tr("Information"),
                                    self.tr("You may only have one database"
                                            " open at time."))
            DEBUG("Ya existe una base de datos abierta")
            return
        wizard = database_wizard.DatabaseWizard(self)
        wizard.wizardFinished.connect(
            self.__on_wizard_finished)
        # Hide menubar and toolbar
        pireal = Pireal.get_service("pireal")
        pireal.show_hide_menubar()
        pireal.show_hide_toolbar()
        # Add wizard widget to stacked
        self.add_widget(wizard)

    def __on_wizard_finished(self, data, wizard_widget):
        """ This slot execute when wizard to create a database is finished """

        pireal = Pireal.get_service("pireal")
        if not data:
            # If it's canceled, remove wizard widget and return to Start Page
            self.remove_last_widget()
        else:
            # Create a new data base container
            db_container = database_container.DatabaseContainer()
            # Associate the file name with the PFile object
            pfile_object = pfile.File(data['filename'])
            # Associate PFile object with data base container
            # and add widget to stacked
            db_container.pfile = pfile_object
            self.add_widget(db_container)
            # Remove wizard
            self.stacked.removeWidget(wizard_widget)
            # Set window title
            pireal.change_title(file_manager.get_basename(data['filename']))
            # Enable db actions
            pireal.set_enabled_db_actions(True)
            pireal.set_enabled_relation_actions(True)
            self.created = True
            DEBUG("Base de datos creada correctamente: '{}'".format(
                data['filename']))

        # If data or not, show menubar and toolbar again
        pireal.show_hide_menubar()
        pireal.show_hide_toolbar()

    def open_database(self, filename=''):
        """ This function opens a database and set this on the UI """

        # If not filename provide, then open dialog to select
        if self.created:
            QMessageBox.information(self,
                                    self.tr("Information"),
                                    self.tr("You may only have one database"
                                            " open at time."))
            DEBUG("Ya existe una base de datos abierta")
            return
        if not filename:
            if self.__last_open_folder is None:
                directory = os.path.expanduser("~")
            else:
                directory = self.__last_open_folder
            filter_ = settings.SUPPORTED_FILES.split(';;')[0]
            filename, _ = QFileDialog.getOpenFileName(self,
                                                      self.tr("Open Database"),
                                                      directory,
                                                      filter_)
            # If is canceled, return
            if not filename:
                return

            # Remember the folder
            self.__last_open_folder = file_manager.get_path(filename)

        DEBUG("Abriendo la base de datos: '{}'".format(filename))

        # If filename provide
        try:
            # Read pdb file
            pfile_object = pfile.File(filename)
            db_data = pfile_object.read()
            # Create a dict to manipulate data more easy
            db_data = self.__sanitize_data(db_data)
        except Exception as reason:
            QMessageBox.information(self,
                                    self.tr("The file couldn't be open"),
                                    str(reason))
            CRITICAL("Error al intentar abrir el archivo: {}".format(reason))
            return

        # Create a database container widget
        db_container = database_container.DatabaseContainer()

        try:
            db_container.create_database(db_data)
        except Exception as reason:
            QMessageBox.information(self,
                                    self.tr("Error"),
                                    str(reason))
            CRITICAL("Error al crear la base de datos: {}".format(reason))
            return

        # Set the PFile object to the new database
        db_container.pfile = pfile_object
        # Add data base container to stacked
        self.add_widget(db_container)
        # Database name
        db_name = file_manager.get_basename(filename)
        # Update title with the new database name, and enable some actions
        pireal = Pireal.get_service("pireal")
        pireal.change_title(db_name)
        pireal.set_enabled_db_actions(True)
        pireal.set_enabled_relation_actions(True)
        # Add to recent databases
        self.recent_databases = filename
        self.created = True

    def open_query(self):
        filter_ = settings.SUPPORTED_FILES.split(';;')[1]
        filename, _ = QFileDialog.getOpenFileName(self,
                                                  self.tr("Open Query"),
                                                  os.path.expanduser("~"),
                                                  filter_)
        if not filename:
            return
        # FIXME: mejorar éste y new_query
        self.new_query(filename)

    def save_query(self, editor=None):
        db = self.get_active_db()
        fname = db.save_query(editor)
        if fname:
            self.querySaved.emit(self.tr("Query saved: {}".format(fname)))

    def save_query_as(self):
        pass

    def __sanitize_data(self, data):
        """
        This function converts the data into a dictionary
        for better handling then.
        The argument 'data' is the content of the database.
        """

        # FIXME: controlar cuando al final de la línea hay una coma
        data_dict = {'tables': []}

        for line_count, line in enumerate(data.splitlines()):
            # Ignore blank lines
            if not line:
                continue
            if line.startswith('@'):
                # This line is a header
                tpoint = line.find(':')
                if tpoint == -1:
                    raise Exception("Invalid syntax at line {}".format(
                        line_count + 1))

                table_name, line = line.split(':')
                table_name = table_name[1:].strip()

                table_dict = {}
                table_dict['name'] = table_name
                table_dict['header'] = line.split(',')
                table_dict['tuples'] = []
            else:
                for l in csv.reader([line]):
                    # Remove spaces
                    l = list(map(str.strip, l))
                    # FIXME: this is necesary?
                    if table_dict['name'] == table_name:
                        table_dict['tuples'].append(l)
            if not table_dict['tuples']:
                data_dict['tables'].append(table_dict)

        return data_dict

    def remove_last_widget(self):
        """ Remove last widget from stacked """

        widget = self.stacked.widget(self.stacked.count() - 1)
        self.stacked.removeWidget(widget)

    def close_database(self):
        """ Close the database and return to the main widget """

        db = self.get_active_db()
        query_container = db.query_container

        if db.modified:
            msgbox = QMessageBox(self)
            msgbox.setIcon(QMessageBox.Question)
            msgbox.setWindowTitle(self.tr("Save Changes?"))
            msgbox.setText(self.tr("The <b>{}</b> database has ben"
                                   " modified.<br>Do you want save "
                                   "your changes?".format(
                                       db.dbname())))
            cancel_btn = msgbox.addButton(self.tr("Cancel"),
                                          QMessageBox.RejectRole)
            msgbox.addButton(self.tr("No"),
                             QMessageBox.NoRole)
            yes_btn = msgbox.addButton(self.tr("Yes"),
                                       QMessageBox.YesRole)
            msgbox.exec_()
            r = msgbox.clickedButton()
            if r == cancel_btn:
                return
            if r == yes_btn:
                self.save_database()

        # Check if editor is modified
        query_widget = query_container.currentWidget()
        if query_widget is not None:
            weditor = query_widget.get_editor()
            if weditor is not None:
                # TODO: duplicate code, see tab widget
                if weditor.modified:
                    msgbox = QMessageBox(self)
                    msgbox.setIcon(QMessageBox.Question)
                    msgbox.setWindowTitle(self.tr("File modified"))
                    msgbox.setText(self.tr("The file <b>{}</b> has unsaved "
                                           "changes. You want to keep "
                                           "them?".format(
                                               weditor.name)))
                    cancel_btn = msgbox.addButton(self.tr("Cancel"),
                                                  QMessageBox.RejectRole)
                    msgbox.addButton(self.tr("No"),
                                     QMessageBox.NoRole)
                    yes_btn = msgbox.addButton(self.tr("Yes"),
                                               QMessageBox.YesRole)
                    msgbox.exec_()
                    r = msgbox.clickedButton()
                    if r == cancel_btn:
                        return
                    if r == yes_btn:
                        self.save_query(weditor)

        self.stacked.removeWidget(db)

        pireal = Pireal.get_service("pireal")
        pireal.set_enabled_db_actions(False)
        pireal.set_enabled_relation_actions(False)
        pireal.set_enabled_query_actions(False)
        pireal.set_enabled_editor_actions(False)
        self.created = False
        DEBUG("Se cerró la base de datos: '{}'".format(db.dbname()))
        del db

    def new_query(self, filename=''):
        pireal = Pireal.get_service("pireal")
        db_container = self.get_active_db()
        db_container.new_query(filename)
        # Enable editor actions
        # FIXME: refactoring
        pireal.set_enabled_query_actions(True)
        zoom_in_action = Pireal.get_action("zoom_in")
        zoom_in_action.setEnabled(True)
        zoom_out_action = Pireal.get_action("zoom_out")
        zoom_out_action.setEnabled(True)
        paste_action = Pireal.get_action("paste_action")
        paste_action.setEnabled(True)
        comment_action = Pireal.get_action("comment")
        comment_action.setEnabled(True)
        uncomment_action = Pireal.get_action("uncomment")
        uncomment_action.setEnabled(True)

    def execute_queries(self):
        db_container = self.get_active_db()
        db_container.execute_queries()

    def execute_selection(self):
        db_container = self.get_active_db()
        db_container.execute_selection()

    def save_database(self):

        db = self.get_active_db()
        if not db.modified:
            return

        # Get relations dict
        relations = db.table_widget.relations
        # Generate content
        content = file_manager.generate_database(relations)
        db.pfile.save(content=content)
        filename = db.pfile.filename
        # Emit signal
        self.databaseSaved.emit(
            self.tr("Database saved: {}".format(filename)))

        db.modified = False

    def save_database_as(self):
        filter = settings.SUPPORTED_FILES.split(';;')[0]
        filename, _ = QFileDialog.getSaveFileName(self,
                                                  self.tr("Save Database As"),
                                                  settings.PIREAL_PROJECTS,
                                                  filter)
        if not filename:
            return
        db = self.get_active_db()
        # Get relations
        relations = db.table_widget.relations
        # Content
        content = file_manager.generate_database(relations)
        db.pfile.save(content, filename)
        self.databaseSaved.emit(
            self.tr("Database saved: {}".format(db.pfile.filename)))

        db.modified = False

    def remove_relation(self):
        db = self.get_active_db()
        if db.delete_relation():
            db.modified = True

    def create_new_relation(self):
        data = new_relation_dialog.create_relation()
        if data is not None:
            db = self.get_active_db()
            rela, rela_name = data
            # Add table
            db.table_widget.add_table(rela, rela_name)
            # Add item to lateral widget
            db.lateral_widget.add_item(rela_name, rela.count())
            # Set modified db
            db.modified = True

    def edit_relation(self):
        db = self.get_active_db()
        lateral = db.lateral_widget
        selected_items = lateral.selectedItems()
        if selected_items:
            selected_relation = selected_items[0].text(0)
            relation_text = selected_relation.split()[0].strip()
            rela = db.table_widget.relations[relation_text]
            data = edit_relation_dialog.edit_relation(rela)
            if data is not None:
                # Update table
                db.table_widget.update_table(data)
                # Update relation
                db.table_widget.relations[relation_text] = data
                # Set modified db
                db.modified = True
                lateral.update_item(data.count())

    def load_relation(self, filename=''):
        """ Load Relation file """

        if not filename:
            if self.__last_open_folder is None:
                directory = os.path.expanduser("~")
            else:
                directory = self.__last_open_folder

            msg = self.tr("Open Relation File")
            filter_ = settings.SUPPORTED_FILES.split(';;')[-1]
            filenames = QFileDialog.getOpenFileNames(self, msg, directory,
                                                     filter_)[0]

            if not filenames:
                return

        # Save folder
        self.__last_open_folder = file_manager.get_path(filenames[0])
        db_container = self.get_active_db()
        if db_container.load_relation(filenames):
            db_container.modified = True

    def add_start_page(self):
        """ This function adds the Start Page to the stacked widget """

        sp = start_page.StartPage()
        self.add_widget(sp)

    def show_settings(self):
        """ Show settings dialog on stacked """

        preferences_dialog = preferences.Preferences(self)

        if isinstance(self.widget(1), preferences.Preferences):
            self.widget(1).close()
        else:
            self.stacked.insertWidget(1, preferences_dialog)
            self.stacked.setCurrentIndex(1)

        # Connect the closed signal
        preferences_dialog.settingsClosed.connect(self._settings_closed)

    def widget(self, index):
        """ Returns the widget at the given index """

        return self.stacked.widget(index)

    def add_widget(self, widget):
        """ Appends and show the given widget to the Stacked """

        index = self.stacked.addWidget(widget)
        self.stacked.setCurrentIndex(index)

    def _settings_closed(self):
        self.stacked.removeWidget(self.widget(1))
        self.stacked.setCurrentWidget(self.stacked.currentWidget())

    def get_active_db(self):
        """ Return an instance of DatabaseContainer widget if the
        stacked contains an DatabaseContainer in last index or None if it's
        not an instance of DatabaseContainer """

        index = self.stacked.count() - 1
        widget = self.widget(index)
        if isinstance(widget, database_container.DatabaseContainer):
            return widget
        return None

    def get_unsaved_queries(self):
        query_container = self.get_active_db().query_container
        return query_container.get_unsaved_queries()

    def undo_action(self):
        query_container = self.get_active_db().query_container
        query_container.undo()

    def redo_action(self):
        query_container = self.get_active_db().query_container
        query_container.redo()

    def cut_action(self):
        query_container = self.get_active_db().query_container
        query_container.cut()

    def copy_action(self):
        query_container = self.get_active_db().query_container
        query_container.copy()

    def paste_action(self):
        query_container = self.get_active_db().query_container
        query_container.paste()

    def zoom_in(self):
        query_container = self.get_active_db().query_container
        query_container.zoom_in()

    def zoom_out(self):
        query_container = self.get_active_db().query_container
        query_container.zoom_out()

    def comment(self):
        query_container = self.get_active_db().query_container
        query_container.comment()

    def uncomment(self):
        query_container = self.get_active_db().query_container
        query_container.uncomment()
class GuiSubscreenBuilder:
    def __init__(self):
        self.widget = QWidget()
        self.main_layout = QGridLayout()
        self.gui_menu_builder = GuiMenuBuilder()
        self.gui_element_builder = GuiElementsBuilder()
        self.foreground_color = ""
        self.central_widget = QStackedWidget()
        self.buttons = []

    def init_with_config(self, config: dict, observer: Observer) -> QWidget:
        self.widget = Base(observer, config["name"], config["Background"])
        self.foreground_color = config["Background"]
        if config["layout"] == 1:
            # Header
            self.main_layout.addWidget(
                self.gui_element_builder.get_svg_widget(
                    Gui_Element.BUTTON, 20, 640, self.foreground_color), 0, 1,
                1, 3, Qt.AlignTop)
            self.main_layout.addWidget(
                self.gui_element_builder.get_svg_widget(
                    Gui_Element.END_RIGHT, 20, 20, self.foreground_color), 0,
                5, Qt.AlignTop)

            self.main_layout.addWidget(self.central_widget, 1, 1, 2, 4)
            # self.central_widget.setStyleSheet("background-color:" + "#ffffff")  # Show size of Central_Widget
            # Footer
            self.main_layout.addWidget(
                self.gui_element_builder.get_svg_widget(
                    Gui_Element.BUTTON, 13, 640, self.foreground_color), 4, 1,
                1, 2, Qt.AlignBottom)
            self.main_layout.addWidget(
                self.gui_element_builder.get_svg_widget(
                    Gui_Element.END_RIGHT, 13, 10, self.foreground_color), 4,
                5, Qt.AlignLeft | Qt.AlignBottom)

            if "subapp" in config:
                self.main_layout.addLayout(
                    self.gui_menu_builder.build_menu(config.get("subapp"),
                                                     self.foreground_color), 0,
                    0, 5, 1)
                self.buttons = self.gui_menu_builder.get_button_list()

                for i in range(0, len(config.get("subapp"))):
                    widget = self.create_subapp(
                        config.get("subapp")[i], observer)
                    button = self.buttons[i]
                    self.central_widget.insertWidget(i, widget)
                    button.clicked.connect(
                        lambda state, wid=widget: self.central_widget.
                        setCurrentWidget(wid))

            self.widget.setLayout(self.main_layout)
            return self.widget
        else:
            return self.create_subapp(config, observer)

    @staticmethod
    def create_subapp(config: dict, observer: Observer) -> QWidget:
        name = config["name"]
        # ToDo besseren Weg zum Erstellen der Subapps suchen
        # ToDo Laden der Subscreens aus Verzeichniss je nach Nennung in Config
        if name == "Clock":
            return Clock(observer, name, config["Background"])
        elif name == "Timer":
            return Timer(observer, name, config["Background"])
        elif name == "Weather":
            return Weather(observer, name, config["Background"], "LCARSGTJ3")
        elif name == "Countup":
            return Countup(name, config["Background"])
        elif name == "Movesub":
            return Movesub(name, config["Background"])
        elif name == "Alarm":
            return Alarm(observer, name, config["Background"], None)
        elif name == "MyCustomEventTest":
            return MyCustomEventTest(name, config["Background"])
        else:
            return Placeholder(name, config["Background"])
Beispiel #32
0
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        
        self.setWindowTitle('Code Size Visualizer')
        
        self.stacked_widget = QStackedWidget() #to show different pages
        self.stacked_widget.currentChanged.connect(self.set_button_state)
        
        
        widget = QtWidgets.QWidget()
        self.setCentralWidget(widget)
     
        vbox = QVBoxLayout()
        vbox.addWidget(self.stacked_widget)
        
        
        #add the to the main window
        self.toolbar = QToolBar("Edit", self)
          
        #on file upload chart button gets enables and upon pressing it goes to next page  
        h = HomeScreen(self) #calling this first
        self.chartBtn = h.viewChartBtn
        self.lineEdit = h.lineEdit
        self.chartBtn.clicked.connect(self.next_page)
        h.pushButton.clicked.connect(self.file_open)
        self.insert_page(h.centralwidget)
        
        self.addToolBar(self.toolbar)
        
        #start with the toolbar hidden
        self.toolbar.toggleViewAction().setChecked(True)
        self.toolbar.toggleViewAction().trigger()
        
        # create main layout
        widget.setLayout(vbox)

    #FILE OPEN    
    def file_open(self):
        name, _ = QtWidgets.QFileDialog.getOpenFileName(None, 'Open File', "", "*.map",options=QtWidgets.QFileDialog.DontUseNativeDialog)
        self.lineEdit.setText(name)
        chartData, navData = FileOpen.openFile(name)
        navigation = Navigation(chartData, navData , self)
        self.addToolBar(navigation.toolbar)
        self.insert_page(navigation.horizontalGroupBox)
      
        
    def set_button_state(self, index):
        n_pages = len(self.stacked_widget)
        self.chartBtn.setEnabled( index % n_pages < n_pages - 1)
        
        
    def insert_page(self, widget, index=-1):
        self.stacked_widget.insertWidget(index, widget)
        self.set_button_state(self.stacked_widget.currentIndex())
        

    def next_page(self):
        new_index = self.stacked_widget.currentIndex()+1
        if new_index < len(self.stacked_widget):
            self.stacked_widget.setCurrentIndex(new_index)
            self.toolbar.toggleViewAction().trigger()