class ComboTabWidget(QWidget): def __init__(self, parent): super(ComboTabWidget, self).__init__(parent) layout = QVBoxLayout(self) layout.setSpacing(0) self.switchCombo = QComboBox(self) layout.addWidget(self.switchCombo, 0, Qt.AlignCenter) groupBox = QGroupBox(self) groupBoxLayout = QVBoxLayout(groupBox) groupBoxLayout.setSpacing(0) self.pageArea = QStackedWidget(groupBox) groupBoxLayout.addWidget(self.pageArea) layout.addWidget(groupBox, 1) self.switchCombo.currentIndexChanged.connect(self.pageArea.setCurrentIndex) def setTabPosition(self, tabPos): pass def addTab(self, w, tabText): self.pageArea.addWidget(w) self.switchCombo.addItem(tabText) def insertTab(self, pos, w, tabText): self.pageArea.insertWidget(pos, w) self.switchCombo.insertItem(pos, tabText) def removeTab(self, index=-1): if index < 0: index = self.currentIndex() w = self.pageArea.widget(index) self.pageArea.removeWidget(w) self.switchCombo.removeItem(index) def updateTab(self, w, tabText, index=-1): if index < 0: index = self.switchCombo.currentIndex() self.removeTab(index) self.insertTab(index, w, tabText) self.setCurrentIndex(index) def setCurrentIndex(self, index): self.switchCombo.setCurrentIndex(index) def widget(self, index): return self.pageArea.widget(index) def currentIndex(self): return self.switchCombo.currentIndex() def count(self): return self.switchCombo.count()
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setWindowFlags(Qt.FramelessWindowHint) self.setGeometry(geom['win']['g']['x'], geom['win']['g']['y'], geom['win']['g']['w'], geom['win']['g']['h']) self.setStyleSheet(BG_STYLE) self.cw = QStackedWidget() self.setCentralWidget(self.cw) stopby = Stopat(IMAGES, self, options = VLC_OPTIONS) self.cw.insertWidget(STOPAT_NDX, stopby) self.cw.setCurrentIndex(STOPAT_NDX) def getstack(self): return self.cw
class E4SideBar(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) """ QWidget.__init__(self, 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.trUtf8("Deselect to activate automatic collapsing")) self.barLayout = QBoxLayout(QBoxLayout.LeftToRight) self.barLayout.setMargin(0) self.layout = QBoxLayout(QBoxLayout.TopToBottom) self.layout.setMargin(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.connect(self.__delayTimer, SIGNAL("timeout()"), 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 = E4SideBar.North if orientation is None: orientation = E4SideBar.North self.setOrientation(orientation) self.connect(self.__tabBar, SIGNAL("currentChanged(int)"), self.__stackedWidget, SLOT("setCurrentIndex(int)")) self.connect(e4App(), SIGNAL("focusChanged(QWidget*, QWidget*)"), self.__appFocusChanged) self.connect(self.__autoHideButton, SIGNAL("toggled(bool)"), 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.connect(self.splitter, SIGNAL("splitterMoved(int, int)"), 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 [E4SideBar.North, E4SideBar.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 [E4SideBar.North, E4SideBar.South]: self.setFixedHeight(self.__tabBar.minimumSizeHint().height()) else: self.setFixedWidth(self.__tabBar.minimumSizeHint().width()) self.__actionMethod = None def expand(self): """ Private method to record a expand request. """ self.__delayTimer.stop() self.__actionMethod = self.__expandIt self.__delayTimer.start() def __expandIt(self): """ Public method to expand the sidebar. """ self.__minimized = False self.__stackedWidget.show() self.resize(self.__bigSize) if self.__orientation in [E4SideBar.North, E4SideBar.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): """ Protected 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 and not self.__stackedWidget.isHidden(): if evt.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 labeltext of the tab (QIcon, string or QString) @param label the labeltext of the tab (string or QString) (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 [E4SideBar.North, E4SideBar.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 or QString) @param label the labeltext of the tab (string or QString) (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 [E4SideBar.North, E4SideBar.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 [E4SideBar.North, E4SideBar.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 == E4SideBar.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 == E4SideBar.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 == E4SideBar.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 == E4SideBar.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 (QString) """ 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 (QString) """ 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 (QString) """ 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 tooltip text text to set (QString) """ 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 (QString) """ 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 WhatsThis text text to set (QString) """ 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 [E4SideBar.North, E4SideBar.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.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 [E4SideBar.North, E4SideBar.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.readUInt16() # version minimized = stream.readBool() if 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. """ self.disconnect(e4App(), SIGNAL("focusChanged(QWidget*, QWidget*)"), self.__appFocusChanged)
class SideBar(QWidget): """ Sidebar with a widget area which is hidden or shown. On by clicking any tab, off by clicking the current tab. """ North = 0 East = 1 South = 2 West = 3 def __init__(self, orientation=2, parent=None): QWidget.__init__(self, parent) self.__tabBar = QTabBar() self.__tabBar.setDrawBase(True) self.__tabBar.setShape(QTabBar.RoundedNorth) self.__tabBar.setFocusPolicy(Qt.NoFocus) self.__tabBar.setUsesScrollButtons(True) self.__tabBar.setElideMode(1) self.__stackedWidget = QStackedWidget(self) self.__stackedWidget.setContentsMargins(0, 0, 0, 0) self.barLayout = QBoxLayout(QBoxLayout.LeftToRight) self.barLayout.setMargin(0) self.layout = QBoxLayout(QBoxLayout.TopToBottom) self.layout.setMargin(0) self.layout.setSpacing(0) self.barLayout.addWidget(self.__tabBar) self.layout.addLayout(self.barLayout) self.layout.addWidget(self.__stackedWidget) self.setLayout(self.layout) self.__minimized = False self.__minSize = 0 self.__maxSize = 0 self.__bigSize = QSize() self.splitter = None self.__tabBar.installEventFilter(self) self.__orientation = orientation self.setOrientation(orientation) self.__tabBar.currentChanged.connect( self.__stackedWidget.setCurrentIndex) return def setSplitter(self, splitter): """ Set the splitter managing the sidebar """ self.splitter = splitter return def __getIndex(self): " Provides the widget index in splitters " if self.__orientation == SideBar.West: return 0 if self.__orientation == SideBar.East: return 2 if self.__orientation == SideBar.South: return 1 return 0 def __getWidget(self): " Provides a reference to the widget " return self.splitter.widget(self.__getIndex()) def shrink(self): """ Shrink the sidebar """ if self.__minimized: return self.__minimized = True self.__bigSize = self.size() if self.__orientation in [SideBar.North, SideBar.South]: self.__minSize = self.minimumHeight() self.__maxSize = self.maximumHeight() else: self.__minSize = self.minimumWidth() self.__maxSize = self.maximumWidth() self.__stackedWidget.hide() sizes = self.splitter.sizes() selfIndex = self.__getIndex() if self.__orientation in [SideBar.North, SideBar.South]: newHeight = self.__tabBar.minimumSizeHint().height() self.setFixedHeight(newHeight) diff = sizes[selfIndex] - newHeight sizes[selfIndex] = newHeight else: newWidth = self.__tabBar.minimumSizeHint().width() self.setFixedWidth(newWidth) diff = sizes[selfIndex] - newWidth sizes[selfIndex] = newWidth if selfIndex == 0: sizes[1] += diff else: sizes[selfIndex - 1] += diff self.splitter.setSizes(sizes) return def expand(self): """ Expand the sidebar """ if not self.__minimized: return self.__minimized = False self.__stackedWidget.show() self.resize(self.__bigSize) sizes = self.splitter.sizes() selfIndex = self.__getIndex() if self.__orientation in [SideBar.North, SideBar.South]: self.setMinimumHeight(self.__minSize) self.setMaximumHeight(self.__maxSize) diff = self.__bigSize.height() - sizes[selfIndex] sizes[selfIndex] = self.__bigSize.height() else: self.setMinimumWidth(self.__minSize) self.setMaximumWidth(self.__maxSize) diff = self.__bigSize.width() - sizes[selfIndex] sizes[selfIndex] = self.__bigSize.width() if selfIndex == 0: sizes[1] -= diff else: sizes[selfIndex - 1] -= diff self.splitter.setSizes(sizes) return def isMinimized(self): """ Provides the minimized state """ return self.__minimized def eventFilter(self, obj, evt): """ Handle click events for the tabbar """ if obj == self.__tabBar: if evt.type() == QEvent.MouseButtonPress: pos = evt.pos() index = self.__tabBar.count() - 1 while index >= 0: if self.__tabBar.tabRect(index).contains(pos): break index -= 1 if index == self.__tabBar.currentIndex(): if self.isMinimized(): self.expand() else: self.shrink() return True elif self.isMinimized(): if self.isTabEnabled(index): self.expand() return QWidget.eventFilter(self, obj, evt) def addTab(self, widget, iconOrLabel, label=None): """ Add a tab to the sidebar """ if label: self.__tabBar.addTab(iconOrLabel, label) else: self.__tabBar.addTab(iconOrLabel) self.__stackedWidget.addWidget(widget) return def insertTab(self, index, widget, iconOrLabel, label=None): """ Insert a tab into the sidebar """ if label: self.__tabBar.insertTab(index, iconOrLabel, label) else: self.__tabBar.insertTab(index, iconOrLabel) self.__stackedWidget.insertWidget(index, widget) return def removeTab(self, index): """ Remove a tab """ self.__stackedWidget.removeWidget(self.__stackedWidget.widget(index)) self.__tabBar.removeTab(index) return def clear(self): """ Remove all tabs """ while self.count() > 0: self.removeTab(0) return def prevTab(self): """ Show the previous tab """ index = self.currentIndex() - 1 if index < 0: index = self.count() - 1 self.setCurrentIndex(index) self.currentWidget().setFocus() return def nextTab(self): """ Show the next tab """ index = self.currentIndex() + 1 if index >= self.count(): index = 0 self.setCurrentIndex(index) self.currentWidget().setFocus() return def count(self): """ Provides the number of tabs """ return self.__tabBar.count() def currentIndex(self): """ Provides the index of the current tab """ return self.__stackedWidget.currentIndex() def setCurrentIndex(self, index): """ Switch to the certain tab """ if index >= self.currentIndex(): return self.__tabBar.setCurrentIndex(index) self.__stackedWidget.setCurrentIndex(index) if self.isMinimized(): self.expand() return def currentWidget(self): """ Provide a reference to the current widget """ return self.__stackedWidget.currentWidget() def setCurrentWidget(self, widget): """ Set the current widget """ self.__stackedWidget.setCurrentWidget(widget) self.__tabBar.setCurrentIndex(self.__stackedWidget.currentIndex()) if self.isMinimized(): self.expand() return def indexOf(self, widget): """ Provides the index of the given widget """ return self.__stackedWidget.indexOf(widget) def isTabEnabled(self, index): """ Check if the tab is enabled """ return self.__tabBar.isTabEnabled(index) def setTabEnabled(self, index, enabled): """ Set the enabled state of the tab """ self.__tabBar.setTabEnabled(index, enabled) return def orientation(self): """ Provides the orientation of the sidebar """ return self.__orientation def setOrientation(self, orient): """ Set the orientation of the sidebar """ if orient == SideBar.North: self.__tabBar.setShape(QTabBar.RoundedNorth) self.barLayout.setDirection(QBoxLayout.LeftToRight) self.layout.setDirection(QBoxLayout.TopToBottom) self.layout.setAlignment(self.barLayout, Qt.AlignLeft) elif orient == SideBar.East: self.__tabBar.setShape(QTabBar.RoundedEast) self.barLayout.setDirection(QBoxLayout.TopToBottom) self.layout.setDirection(QBoxLayout.RightToLeft) self.layout.setAlignment(self.barLayout, Qt.AlignTop) elif orient == SideBar.South: self.__tabBar.setShape(QTabBar.RoundedSouth) self.barLayout.setDirection(QBoxLayout.LeftToRight) self.layout.setDirection(QBoxLayout.BottomToTop) self.layout.setAlignment(self.barLayout, Qt.AlignLeft) else: # default orient = SideBar.West self.__tabBar.setShape(QTabBar.RoundedWest) self.barLayout.setDirection(QBoxLayout.TopToBottom) self.layout.setDirection(QBoxLayout.LeftToRight) self.layout.setAlignment(self.barLayout, Qt.AlignTop) self.__orientation = orient return def tabIcon(self, index): """ Provide the icon of the tab """ return self.__tabBar.tabIcon(index) def setTabIcon(self, index, icon): """ Set the icon of the tab """ self.__tabBar.setTabIcon(index, icon) return def tabText(self, index): """ Provide the text of the tab """ return self.__tabBar.tabText(index) def setTabText(self, index, text): """ Set the text of the tab """ self.__tabBar.setTabText(index, text) return def tabToolTip(self, index): """ Provide the tooltip text of the tab """ return self.__tabBar.tabToolTip(index) def setTabToolTip(self, index, tip): """ Set the tooltip text of the tab """ self.__tabBar.setTabToolTip(index, tip) return def tabWhatsThis(self, index): """ Provide the WhatsThis text of the tab """ return self.__tabBar.tabWhatsThis(index) def setTabWhatsThis(self, index, text): """ Set the WhatsThis text for the tab """ self.__tabBar.setTabWhatsThis(index, text) return def widget(self, index): """ Provides the reference to the widget (QWidget) """ return self.__stackedWidget.widget(index)
class SideBar( QWidget ): """ Sidebar with a widget area which is hidden or shown. On by clicking any tab, off by clicking the current tab. """ North = 0 East = 1 South = 2 West = 3 def __init__( self, orientation = 2, parent = None ): QWidget.__init__( self, parent ) self.__tabBar = QTabBar() self.__tabBar.setDrawBase( True ) self.__tabBar.setShape( QTabBar.RoundedNorth ) self.__tabBar.setFocusPolicy( Qt.NoFocus ) self.__tabBar.setUsesScrollButtons( True ) self.__tabBar.setElideMode( 1 ) self.__stackedWidget = QStackedWidget( self ) self.__stackedWidget.setContentsMargins( 0, 0, 0, 0 ) self.barLayout = QBoxLayout( QBoxLayout.LeftToRight ) self.barLayout.setMargin( 0 ) self.layout = QBoxLayout( QBoxLayout.TopToBottom ) self.layout.setMargin( 0 ) self.layout.setSpacing( 0 ) self.barLayout.addWidget( self.__tabBar ) self.layout.addLayout( self.barLayout ) self.layout.addWidget( self.__stackedWidget ) self.setLayout( self.layout ) self.__minimized = False self.__minSize = 0 self.__maxSize = 0 self.__bigSize = QSize() self.splitter = None self.__tabBar.installEventFilter( self ) self.__orientation = orientation self.setOrientation( orientation ) self.__tabBar.currentChanged.connect( self.__stackedWidget.setCurrentIndex ) return def setSplitter( self, splitter ): """ Set the splitter managing the sidebar """ self.splitter = splitter return def __getIndex( self ): " Provides the widget index in splitters " if self.__orientation == SideBar.West: return 0 if self.__orientation == SideBar.East: return 2 if self.__orientation == SideBar.South: return 1 return 0 def __getWidget( self ): " Provides a reference to the widget " return self.splitter.widget( self.__getIndex() ) def shrink( self ): """ Shrink the sidebar """ if self.__minimized: return self.__minimized = True self.__bigSize = self.size() if self.__orientation in [ SideBar.North, SideBar.South ]: self.__minSize = self.minimumHeight() self.__maxSize = self.maximumHeight() else: self.__minSize = self.minimumWidth() self.__maxSize = self.maximumWidth() self.__stackedWidget.hide() sizes = self.splitter.sizes() selfIndex = self.__getIndex() if self.__orientation in [ SideBar.North, SideBar.South ]: newHeight = self.__tabBar.minimumSizeHint().height() self.setFixedHeight( newHeight ) diff = sizes[ selfIndex ] - newHeight sizes[ selfIndex ] = newHeight else: newWidth = self.__tabBar.minimumSizeHint().width() self.setFixedWidth( newWidth ) diff = sizes[ selfIndex ] - newWidth sizes[ selfIndex ] = newWidth if selfIndex == 0: sizes[ 1 ] += diff else: sizes[ selfIndex - 1 ] += diff self.splitter.setSizes( sizes ) return def expand( self ): """ Expand the sidebar """ if not self.__minimized: return self.__minimized = False self.__stackedWidget.show() self.resize( self.__bigSize ) sizes = self.splitter.sizes() selfIndex = self.__getIndex() if self.__orientation in [ SideBar.North, SideBar.South ]: self.setMinimumHeight( self.__minSize ) self.setMaximumHeight( self.__maxSize ) diff = self.__bigSize.height() - sizes[ selfIndex ] sizes[ selfIndex ] = self.__bigSize.height() else: self.setMinimumWidth( self.__minSize ) self.setMaximumWidth( self.__maxSize ) diff = self.__bigSize.width() - sizes[ selfIndex ] sizes[ selfIndex ] = self.__bigSize.width() if selfIndex == 0: sizes[ 1 ] -= diff else: sizes[ selfIndex - 1 ] -= diff self.splitter.setSizes( sizes ) return def isMinimized( self ): """ Provides the minimized state """ return self.__minimized def eventFilter( self, obj, evt ): """ Handle click events for the tabbar """ if obj == self.__tabBar: if evt.type() == QEvent.MouseButtonPress: pos = evt.pos() index = self.__tabBar.count() - 1 while index >= 0: if self.__tabBar.tabRect( index ).contains( pos ): break index -= 1 if index == self.__tabBar.currentIndex(): if self.isMinimized(): self.expand() else: self.shrink() return True elif self.isMinimized(): if self.isTabEnabled( index ): self.expand() return QWidget.eventFilter( self, obj, evt ) def addTab( self, widget, iconOrLabel, label = None ): """ Add a tab to the sidebar """ if label: self.__tabBar.addTab( iconOrLabel, label ) else: self.__tabBar.addTab( iconOrLabel ) self.__stackedWidget.addWidget( widget ) return def insertTab( self, index, widget, iconOrLabel, label = None ): """ Insert a tab into the sidebar """ if label: self.__tabBar.insertTab( index, iconOrLabel, label ) else: self.__tabBar.insertTab( index, iconOrLabel ) self.__stackedWidget.insertWidget( index, widget ) return def removeTab( self, index ): """ Remove a tab """ self.__stackedWidget.removeWidget( self.__stackedWidget.widget( index ) ) self.__tabBar.removeTab( index ) return def clear( self ): """ Remove all tabs """ while self.count() > 0: self.removeTab( 0 ) return def prevTab( self ): """ Show the previous tab """ index = self.currentIndex() - 1 if index < 0: index = self.count() - 1 self.setCurrentIndex( index ) self.currentWidget().setFocus() return def nextTab( self ): """ Show the next tab """ index = self.currentIndex() + 1 if index >= self.count(): index = 0 self.setCurrentIndex( index ) self.currentWidget().setFocus() return def count( self ): """ Provides the number of tabs """ return self.__tabBar.count() def currentIndex( self ): """ Provides the index of the current tab """ return self.__stackedWidget.currentIndex() def setCurrentIndex( self, index ): """ Switch to the certain tab """ if index >= self.currentIndex(): return self.__tabBar.setCurrentIndex( index ) self.__stackedWidget.setCurrentIndex(index) if self.isMinimized(): self.expand() return def currentWidget( self ): """ Provide a reference to the current widget """ return self.__stackedWidget.currentWidget() def setCurrentWidget( self, widget ): """ Set the current widget """ self.__stackedWidget.setCurrentWidget( widget ) self.__tabBar.setCurrentIndex( self.__stackedWidget.currentIndex() ) if self.isMinimized(): self.expand() return def indexOf( self, widget ): """ Provides the index of the given widget """ return self.__stackedWidget.indexOf( widget ) def isTabEnabled( self, index ): """ Check if the tab is enabled """ return self.__tabBar.isTabEnabled( index ) def setTabEnabled( self, index, enabled ): """ Set the enabled state of the tab """ self.__tabBar.setTabEnabled( index, enabled ) return def orientation( self ): """ Provides the orientation of the sidebar """ return self.__orientation def setOrientation( self, orient ): """ Set the orientation of the sidebar """ if orient == SideBar.North: self.__tabBar.setShape( QTabBar.RoundedNorth ) self.barLayout.setDirection( QBoxLayout.LeftToRight ) self.layout.setDirection( QBoxLayout.TopToBottom ) self.layout.setAlignment( self.barLayout, Qt.AlignLeft ) elif orient == SideBar.East: self.__tabBar.setShape( QTabBar.RoundedEast ) self.barLayout.setDirection( QBoxLayout.TopToBottom ) self.layout.setDirection( QBoxLayout.RightToLeft ) self.layout.setAlignment( self.barLayout, Qt.AlignTop ) elif orient == SideBar.South: self.__tabBar.setShape( QTabBar.RoundedSouth ) self.barLayout.setDirection( QBoxLayout.LeftToRight ) self.layout.setDirection( QBoxLayout.BottomToTop ) self.layout.setAlignment( self.barLayout, Qt.AlignLeft ) else: # default orient = SideBar.West self.__tabBar.setShape( QTabBar.RoundedWest ) self.barLayout.setDirection( QBoxLayout.TopToBottom ) self.layout.setDirection( QBoxLayout.LeftToRight ) self.layout.setAlignment( self.barLayout, Qt.AlignTop ) self.__orientation = orient return def tabIcon( self, index ): """ Provide the icon of the tab """ return self.__tabBar.tabIcon( index ) def setTabIcon( self, index, icon ): """ Set the icon of the tab """ self.__tabBar.setTabIcon( index, icon ) return def tabText( self, index ): """ Provide the text of the tab """ return self.__tabBar.tabText( index ) def setTabText( self, index, text ): """ Set the text of the tab """ self.__tabBar.setTabText( index, text ) return def tabToolTip( self, index ): """ Provide the tooltip text of the tab """ return self.__tabBar.tabToolTip( index ) def setTabToolTip( self, index, tip ): """ Set the tooltip text of the tab """ self.__tabBar.setTabToolTip( index, tip ) return def tabWhatsThis( self, index ): """ Provide the WhatsThis text of the tab """ return self.__tabBar.tabWhatsThis( index ) def setTabWhatsThis( self, index, text ): """ Set the WhatsThis text for the tab """ self.__tabBar.setTabWhatsThis( index, text ) return def widget( self, index ): """ Provides the reference to the widget (QWidget) """ return self.__stackedWidget.widget( index )
class EditorContainer(QWidget): # Señales closedFile = pyqtSignal(int) savedFile = pyqtSignal('QString') cursorPosition = pyqtSignal(int, int, int) updateSymbols = pyqtSignal('PyQt_PyObject') fileChanged = pyqtSignal('QString') openedFile = pyqtSignal('QString') def __init__(self, edis=None): QWidget.__init__(self, edis) self.setAcceptDrops(True) self.box = QVBoxLayout(self) self.box.setContentsMargins(0, 0, 0, 0) self.box.setSpacing(0) # Stacked self.stack = QStackedWidget() self.box.addWidget(self.stack) # Replace widget #FIXME: mover esto self._replace_widget = replace_widget.ReplaceWidget() self._replace_widget.hide() self.box.addWidget(self._replace_widget) # Editor widget self.editor_widget = editor_widget.EditorWidget() # Conexiones self.connect(self.editor_widget, SIGNAL("saveCurrentFile()"), self.save_file) self.connect(self.editor_widget, SIGNAL("fileClosed(int)"), self._file_closed) self.connect(self.editor_widget, SIGNAL("recentFile(QStringList)"), self.update_recents_files) self.connect(self.editor_widget, SIGNAL("allFilesClosed()"), self.add_start_page) self.connect(self.editor_widget, SIGNAL("currentWidgetChanged(int)"), self.change_widget) Edis.load_component("principal", self) def update_recents_files(self, recents_files): """ Actualiza el submenú de archivos recientes """ menu = Edis.get_component("menu_recent_file") self.connect(menu, SIGNAL("triggered(QAction*)"), self._open_recent_file) menu.clear() for _file in recents_files: menu.addAction(_file) def _open_recent_file(self, accion): """ Abre el archivo desde el menú """ self.open_file(accion.text()) def get_recents_files(self): """ Devuelve una lista con los archivos recientes en el menú """ menu = Edis.get_component('menu_recent_file') actions = menu.actions() recents_files = [] for filename in actions: recents_files.append(filename.text()) return recents_files def _file_closed(self, index): self.closedFile.emit(index) def _file_modified(self, value): self.editor_widget.editor_modified(value) def _file_saved(self, filename): self.editor_widget.editor_modified(False) self.emit(SIGNAL("updateSymbols(QString)"), filename) def change_widget(self, index): weditor = self.get_active_editor() self.editor_widget.combo.combo_file.setCurrentIndex(index) if weditor is not None and not weditor.obj_file.is_new: self.emit(SIGNAL("updateSymbols(QString)"), weditor.filename) self.emit(SIGNAL("fileChanged(QString)"), weditor.filename) weditor.setFocus() def create_editor(self, obj_file=None, filename=""): if obj_file is None: obj_file = object_file.EdisFile(filename) self.stack.addWidget(self.editor_widget) # Quito la página de inicio, si está _start_page = self.stack.widget(0) if isinstance(_start_page, start_page.StartPage): self.remove_widget(_start_page) # Detengo el tiimer _start_page.timer.stop() weditor = editor.Editor(obj_file) self.editor_widget.add_widget(weditor) self.editor_widget.add_item_combo(obj_file.filename) lateral = Edis.get_component("tab_container") if not lateral.isVisible(): lateral.show() # Conexiones self.connect(obj_file, SIGNAL("fileChanged(PyQt_PyObject)"), self._file_changed) self.connect(weditor, SIGNAL("cursorPositionChanged(int, int)"), self.update_cursor) self.connect(weditor, SIGNAL("modificationChanged(bool)"), self._file_modified) self.connect(weditor, SIGNAL("fileSaved(QString)"), self._file_saved) self.connect(weditor, SIGNAL("linesChanged(int)"), self.editor_widget.combo.move_to_symbol) self.connect(weditor, SIGNAL("dropEvent(PyQt_PyObject)"), self._drop_editor) self.emit(SIGNAL("fileChanged(QString)"), obj_file.filename) weditor.setFocus() return weditor def _file_changed(self, obj_file): filename = obj_file.filename flags = QMessageBox.Yes flags |= QMessageBox.No result = QMessageBox.information(self, self.tr("Monitoreo de Archivo"), self.tr("El archivo <b>{0}</b> fué " "modificado fuera de Edis. " "<br><br> Quieres recar" "garlo?".format(filename)), flags) if result == QMessageBox.No: return self.reload_file(obj_file) def reload_file(self, obj_file=None): weditor = self.get_active_editor() if weditor is None: return if obj_file is None: obj_file = weditor.obj_file content = obj_file.read() if weditor.is_modified: result = QMessageBox.information(self, self.tr( "Archivo no guardado!"), self.tr("Seguro que quieres recargar el archivo <b>{0}</b>?" "<br><br>" "Se perderán los cambios no guardados.").format( obj_file.filename), QMessageBox.Cancel | QMessageBox.Yes) if result == QMessageBox.Cancel: return weditor.setText(content) weditor.markerDeleteAll() weditor.setModified(False) def open_file(self, filename="", cursor_position=None): filter_files = "Archivos C(*.cpp *.c);;ASM(*.s);;HEADERS(*.h);;(*.*)" if not filename: working_directory = os.path.expanduser("~") weditor = self.get_active_editor() if weditor and weditor.filename: working_directory = self._last_folder(weditor.filename) filenames = QFileDialog.getOpenFileNames(self, self.tr("Abrir Archivo"), working_directory, filter_files) else: filenames = [filename] try: for _file in filenames: if not self._is_open(_file): #self.editor_widget.not_open = False # Creo el objeto Edis File obj_file = object_file.EdisFile(_file) content = obj_file.read() weditor = self.create_editor(obj_file, _file) weditor.setText(content) # Cuando se setea el contenido en el editor # se emite la señal textChanged() por lo tanto se agrega # el marker, entonces se procede a borrarlo weditor.markerDelete(0, 3) # FIXME: Cursor position not found #if cursor_position is not None: #line, row = cursor_position #weditor.setCursorPosition(line, row) weditor.setModified(False) obj_file.run_system_watcher() else: # Se cambia el índice del stacked # para mostrar el archivo que ya fué abierto for index in range(self.editor_widget.count()): editor = self.editor_widget.widget(index) if editor.filename == _file: self.change_widget(index) self.emit(SIGNAL("fileChanged(QString)"), _file) self.emit(SIGNAL("openedFile(QString)"), _file) self.emit(SIGNAL("updateSymbols(QString)"), _file) except EdisIOError as error: ERROR('Error al intentar abrir archivo: %s', error) QMessageBox.critical(self, self.tr('No se pudo abrir el archivo'), str(error)) #self.editor_widget.not_open = True def _last_folder(self, path): """ Devuelve la última carpeta a la que se accedió """ return QFileInfo(path).absolutePath() def _is_open(self, archivo): """ Retorna True si un archivo ya esta abierto, False en caso contrario """ for index in range(self.editor_widget.count()): widget = self.editor_widget.widget(index) if widget.filename == archivo: return True return False def add_widget(self, widget): """ Agrega @widget al stacked """ self.editor_widget.add_widget(widget) def add_start_page(self): """ Agrega la página de inicio al stack """ if settings.get_setting('general/show-start-page'): _start_page = start_page.StartPage() self.stack.insertWidget(0, _start_page) self.stack.setCurrentIndex(0) else: self.editor_widget.combo.setVisible(False) def remove_widget(self, widget): """ Elimina el @widget del stacked """ self.stack.removeWidget(widget) def current_widget(self): """ Widget actual """ return self.editor_widget.current_widget() def current_index(self): return self.editor_widget.current_index() def get_active_editor(self): """ Devuelve el Editor si el widget actual es una instancia de él, de lo contrario devuelve None. """ widget = self.current_widget() if isinstance(widget, editor.Editor): return widget return None def close_file(self): self.editor_widget.close_file() def close_file_from_project(self, filename): #FIXME: revisar for index in range(self.editor_widget.count()): widget = self.editor_widget.widget(index) if widget.filename == filename: editor, i = widget, index self.editor_widget.close_file_project(editor, i) def close_all(self): self.editor_widget.close_all() def show_selector(self): if self.get_active_editor() is not None: selector = file_selector.FileSelector(self) selector.show() def save_file(self, weditor=None): if weditor is None: weditor = self.get_active_editor() if weditor is None: return if weditor.obj_file.is_new: return self.save_file_as(weditor) source_code = weditor.text() weditor.obj_file.write(source_code) weditor.saved() # System watcher weditor.obj_file.run_system_watcher() self.savedFile.emit(weditor.filename) return weditor.filename def save_file_as(self, weditor=None): if weditor is None: weditor = self.get_active_editor() if weditor is None: return working_directory = os.path.expanduser("~") filename = QFileDialog.getSaveFileName(self, self.tr("Guardar Archivo"), working_directory) if not filename: return False content = weditor.text() weditor.obj_file.write(content, filename) weditor.saved() self.fileChanged.emit(weditor.filename) self.savedFile.emit(weditor.filename) return filename def save_selected(self, filename): for index in range(self.editor_widget.count()): if self.editor_widget.widget(index).filename == filename: self.save_file(self.editor_widget.widget(index)) def files_not_saved(self): return self.editor_widget.files_not_saved() def check_files_not_saved(self): return self.editor_widget.check_files_not_saved() def find(self): weditor = self.get_active_editor() if weditor is not None: dialog = find_popup.PopupBusqueda(self.get_active_editor()) dialog.show() def find_and_replace(self): weditor = self.get_active_editor() if weditor is not None: if self._replace_widget.isVisible(): self._replace_widget.hide() weditor.setFocus() else: self._replace_widget.show() def action_undo(self): weditor = self.get_active_editor() if weditor is not None: weditor.undo() def action_redo(self): weditor = self.get_active_editor() if weditor is not None: weditor.redo() def action_cut(self): weditor = self.get_active_editor() if weditor is not None: weditor.cut() def action_copy(self): weditor = self.get_active_editor() if weditor is not None: weditor.copy() def action_paste(self): weditor = self.get_active_editor() if weditor is not None: weditor.paste() def show_tabs_and_spaces(self): weditor = self.get_active_editor() if weditor is not None: tabs_spaces = settings.get_setting('editor/show-tabs-spaces') settings.set_setting('editor/show-tabs-spaces', not tabs_spaces) weditor.update_options() def show_indentation_guides(self): weditor = self.get_active_editor() if weditor is not None: guides = settings.get_setting('editor/show-guides') settings.set_setting('editor/show-guides', not guides) weditor.update_options() def delete_editor_markers(self): weditor = self.get_active_editor() if weditor is not None: weditor.markerDeleteAll() def action_zoom_in(self): weditor = self.get_active_editor() if weditor is not None: weditor.zoom_in() def action_zoom_out(self): weditor = self.get_active_editor() if weditor is not None: weditor.zoom_out() def action_normal_size(self): """ Carga el tamaño por default de la fuente """ weditor = self.get_active_editor() if weditor is not None: weditor.zoomTo(0) def action_select_all(self): weditor = self.get_active_editor() if weditor is not None: weditor.selectAll() def opened_files(self): return self.editor_widget.opened_files() def opened_files_for_selector(self): self.index_file_selector = 0 files = [] for index in range(self.editor_widget.count()): weditor = self.editor_widget.widget(index) path = weditor.filename if not path: path = weditor.display + ' (%s)' % self.index_file_selector self.index_file_selector += 1 files.append(path) return files def get_open_projects(self): tree_projects = Edis.get_lateral("tree_projects") return tree_projects.get_open_projects() def file_properties(self): weditor = self.get_active_editor() if weditor is not None: dialog = file_properties.FileProperty(weditor, self) dialog.show() def update_cursor(self, line, row): weditor = self.get_active_editor() lines = weditor.lines() self.editor_widget.combo.update_cursor_position( line + 1, row + 1, lines) self.cursorPosition.emit(line + 1, row + 1, lines) def build_source_code(self): output = Edis.get_component("output") project = Edis.get_lateral("tree_projects") weditor = self.get_active_editor() if weditor is not None: filename = self.save_file() if project.sources: output.build((filename, project.sources)) else: if filename: output.build((weditor.filename, [])) def run_binary(self): """ Ejecuta el programa objeto """ output = Edis.get_component("output") output.run() def build_and_run(self): output = Edis.get_component("output") weditor = self.get_active_editor() if weditor is not None: self.save_file() output.build_and_run(weditor.filename) def clean_construction(self): output = Edis.get_component("output") output.clean() def stop_program(self): output = Edis.get_component("output") output.stop() def action_comment(self): weditor = self.get_active_editor() if weditor is not None: weditor.comment() def action_uncomment(self): weditor = self.get_active_editor() if weditor is not None: weditor.uncomment() def action_indent(self): weditor = self.get_active_editor() if weditor is not None: weditor.indent_more() def action_unindent(self): weditor = self.get_active_editor() if weditor is not None: weditor.indent_less() def action_to_lowercase(self): weditor = self.get_active_editor() if weditor is not None: weditor.to_lowercase() def action_to_uppercase(self): weditor = self.get_active_editor() if weditor is not None: weditor.to_uppercase() def action_to_title(self): weditor = self.get_active_editor() if weditor is not None: weditor.to_title() def action_duplicate_line(self): weditor = self.get_active_editor() if weditor is not None: weditor.duplicate_line() def action_delete_line(self): weditor = self.get_active_editor() if weditor is not None: weditor.delete_line() def action_move_down(self): weditor = self.get_active_editor() if weditor is not None: weditor.move_down() def action_move_up(self): weditor = self.get_active_editor() if weditor is not None: weditor.move_up() def reemplazar_tabs_por_espacios(self): weditor = self.get_active_editor() if weditor is not None: weditor.reemplazar_tabs_por_espacios() def go_to_line(self, line): weditor = self.get_active_editor() if weditor is not None: weditor.setCursorPosition(line, 0) def show_go_to_line(self): weditor = self.get_active_editor() if weditor is not None: dialog = goto_line_widget.GoToLineDialog(weditor) dialog.show() def add_symbols_combo(self, symbols): self.editor_widget.add_symbols(symbols) def dragEnterEvent(self, event): data = event.mimeData() if data.hasText(): # Se acepta el evento de arrastrado event.accept() def dropEvent(self, event): self._drop_event(event) def _drop_editor(self, event): self._drop_event(event) def _drop_event(self, event): data = event.mimeData() filename = data.urls()[0].toLocalFile() self.open_file(filename) def show_settings(self): preferences_widget = Edis.get_component("preferences") current_widget = self.stack.currentWidget() if isinstance(current_widget, preferences_widget.__class__): return self.connect(preferences_widget, SIGNAL("configurationsClose(PyQt_PyObject)"), lambda widget: self.remove_widget(widget)) index = self.stack.addWidget(preferences_widget) self.stack.setCurrentIndex(index) def open_project(self, filename='', edis_project=True): if edis_project: if not filename: filename = QFileDialog.getOpenFileName(self, self.tr("Cargar " "Proyecto"), paths.PROJECT_DIR, "Archivo Edis(*.epf)") if not filename: return project_file = json.load(open(filename)) project_path = project_file.get('path', '') else: project_path = os.path.dirname(filename) else: result = QFileDialog.getExistingDirectory(self, self.tr("Selecciona " "la carpeta")) if not result: return project_path = result project_structure = {} filter_files = ['.c', '.h'] for parent, dirs, files in os.walk(project_path): files = [fi for fi in files if os.path.splitext(fi)[-1] in filter_files] project_structure[parent] = (files, dirs) self.emit(SIGNAL("projectOpened(PyQt_PyObject)"), (project_structure, project_path, edis_project, filename)) def open_directory(self): self.open_project(edis_project=False) def create_new_project(self): project_creator = new_project.NewProjectDialog(self) self.connect(project_creator, SIGNAL("projectReady(PyQt_PyObject)"), self._update_data) project_creator.show() def _update_data(self, data): self.emit(SIGNAL("projectReady(PyQt_PyObject)"), data) def opened_projects(self): pass def code_pasting(self): if self.get_active_editor() is not None: code = self.get_active_editor().text() code_pasting = code_pasting_dialog.CodePastingDialog(self, code) code_pasting.exec_() def show_snake(self): from src.ui.widgets.pyborita import pyborita_widget w = pyborita_widget.PyboritaWidget(self) toolbar = Edis.get_component("toolbar") lateral = Edis.get_component("tab_container") status = Edis.get_component("status_bar") output = Edis.get_component("output") widgets = [toolbar, status, lateral, output] for widget in widgets: widget.hide() self.stack.insertWidget(0, w) self.stack.setCurrentIndex(0)
class FragmentFrame(QFrame): # Signals: SIG_REMOVE_FRAGMENT = 'removeFragment()' # Fragment edition switch FRAGMENT_EDITION = False view = None fetcher = None def __init__(self, fragment, args, client, animation_manager=None, parent=None, has_menu_pos=True): """ @fragment [Fragment] user_settings.Fragment object to describe fragment @client [RpcdClient] client @parent [QWidget] parent widget """ #assert isinstance(client, RpcdClient) assert frag_types.has_key(fragment.type) QFrame.__init__(self, parent) self.animation_manager = animation_manager self.has_menu_pos = has_menu_pos self.fragment = fragment self.fetcher = frag_types[fragment.type].fetcher(fragment, args, client) self.connect(self.fetcher, SIGNAL(self.fetcher.ERROR_SIGNAL), self.errorHandler) self.window = parent self.cumulative_mode = False self.interval = Interval('daily') self.setFragmentColor() self.setFrameShadow(QFrame.Sunken) self.setFrameShape(QFrame.StyledPanel) self.setContextMenuPolicy(Qt.ActionsContextMenu) self.toolspace = None self.vbox = QVBoxLayout() # self.vbox.setContentsMargins(9,0,9,9) self.vbox.setContentsMargins(9,0,9,0) self.setLayout(self.vbox) self.stacked = QStackedWidget(self) updating_label = QLabel("<img src=\":/icons/refresh.png\" /><br />%s" % self.tr("Updating...")) updating_label.setAlignment(Qt.AlignHCenter|Qt.AlignVCenter) self.stacked.addWidget(updating_label) # Create all actions for the rightclick context menu self.action_list = [] self.switch_actions = {} self.viewlayout = QHBoxLayout() self.viewlayout.setContentsMargins(0,0,0,0) self.viewlayout.setSpacing(2) self.viewlayout.addStretch() widget = QWidget() widget.setLayout(self.viewlayout) self.vbox.addWidget(widget) self.line = QFrame(self) self.line.setFrameShape(QFrame.HLine) self.line.setFrameShadow(QFrame.Sunken) self.line.setObjectName("line") # Menu to choose position of fragment if self.has_menu_pos: self.pos_menu = QMenu(tr('Position'), self) # self.pos_action = QAction(tr('Position'), self.pos_menu) def make_lambda(l): """ usefull to create the lambda function with a copied parameter. or it'll bug """ return lambda: QTimer.singleShot(0, lambda: self.setView(l)) self.buttons = [] button = QToolButton() button.visible = True button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Ignored) button.setMinimumSize(0,16) button.setIcon(QIcon(":/icons/refresh.png")) button.setFixedHeight(16) button.setToolTip(tr("Refresh")) self.connect(button, SIGNAL("clicked()"), self.updateData) self.viewlayout.addWidget(button) self.buttons.append(button) # All of the views available for this kind of fragment. if len(frag_types[fragment.type].views) > 1: for label in frag_types[fragment.type].views: try: item_name = views_list_label[label] except KeyError: continue # item_name returns a unicode string, but PyQT (Qt 4.2.1) won't convert it to a char* # unless we convert it to a non-unicode string .... action = QAction(QIcon(':/icons/%s' % label), tr("Switch to %s") % self.tr(unicode(item_name)), self) self.connect(action, SIGNAL("triggered()"), make_lambda(label)) self.action_list += [action] self.switch_actions[label] = action button = QToolButton() button.visible = True button.setBackgroundRole(QPalette.Button) button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Minimum) button.setMinimumSize(0,16) button.setFixedHeight(16) button.setIcon(QIcon(":/icons/%s" % label)) button.setToolTip(tr("Switch to %s") % self.tr(unicode(item_name))) self.connect(button, SIGNAL("clicked()"), make_lambda(label)) self.viewlayout.addWidget(button) self.buttons.append(button) # Separator action = QAction(self) action.setSeparator(True) self.action_list += [action] # Refresh action = QAction(QIcon(':/icons/refresh.png'), tr('Refresh'), self) self.connect(action, SIGNAL('triggered()'), self.updateData) self.action_list += [action] if self.FRAGMENT_EDITION: # Edit action = QAction(QIcon(':/icons/edit.png'), tr('Edit this fragment...'), self) self.connect(action, SIGNAL('triggered()'), self.editFragment) self.action_list += [action] # Delete action = QAction(QIcon(':/icons/moins.png'), tr('Delete this fragment'), self) self.connect(action, SIGNAL('triggered()'), self.removeFragment) self.action_list += [action] self.setView(fragment.view, update=False) self.setAcceptDrops(True) self.pos = -1 def mouseMoveEvent(self, event): if event.buttons() != Qt.LeftButton: return mimeData = QMimeData() if self.pos == -1: return mimeData.setData("splitter/fragment", QByteArray.number(self.pos)) drag = QDrag(self) drag.setMimeData(mimeData) drag.setHotSpot(event.pos() - self.rect().topLeft()) dropAction = drag.start(Qt.MoveAction) if dropAction == Qt.MoveAction: self.close() def dragEnterEvent(self, event): event.accept() def dropEvent(self, event): data = event.mimeData().data("splitter/fragment").toInt() if not data[1]: return frame_pos = data[0] if frame_pos == self.pos: return event.setDropAction(Qt.MoveAction) event.accept() self.window.changedPositionFragment(self.pos, frame_pos) # def __del__(self): # self.destructor() def destructor(self): if self.view: self.freeView() if self.fetcher: self.disconnect(self.fetcher, SIGNAL(self.fetcher.ERROR_SIGNAL), self.errorHandler) self.fetcher.destructor() self.fetcher = None def getView(self): return self.view def getFragment(self): return self.fragment def setCumulative(self, cumulative): self.cumulative_mode = cumulative if self.view: self.view.setCumulative(cumulative) def setInterval(self, interval): self.interval = interval if self.view: self.view.setInterval(interval) def setFragmentColor(self): # XXX: We have to put classes which we colorize, because some objects bug # when we try to put a background on them. For example, do NOT colorize # QScrollBar, it'll not work anyway: # http://doc.trolltech.com/4.4/stylesheet-examples.html#customizing-qscrollbar # "The QScrollBar can be styled using its subcontrols like handle, # add-line, sub-line, and so on. Note that if one property or # sub-control is customized, all the other properties or sub-controls # must be customized as well." self.setStyleSheet(""" QFrame, QPushButton, QTableCornerButton, QAbstractSpinBox, QLineEdit { background-color: #%06X; } """ % self.fragment.background_color) def editFragment(self): if AddFragDialog(self.window, self.fragment, self).run(): self.setFragmentColor() self.setView(self.fragment.view, update=True) def removeFragment(self): reply = QMessageBox.question(self, self.tr("Delete a fragment"), unicode(self.tr('Are you sure to delete the fragment "%s" from the view?')) % self.fragment.title, QMessageBox.Yes|QMessageBox.No) if reply == QMessageBox.Yes: QTimer.singleShot(0, self._removeFragment_emit) def _removeFragment_emit(self): self.emit(SIGNAL(self.SIG_REMOVE_FRAGMENT)) # def resizeEvent(self, event): # QFrame.resizeEvent(self, event) # self.view.resize(event.size()) def freeView(self): if self.view: self.view.destructor() self.disconnect(self.view, SIGNAL('open_page'), self._open_page) self.disconnect(self.view, SIGNAL('add_filter'), self._add_filter) self.disconnect(self.view, SIGNAL('updating'), self._show_animation) self.disconnect(self.view, SIGNAL('updated'), self._show_view) self.disconnect(self.view, SIGNAL('EAS_Message'), self.EAS_SendMessage) self.stacked.removeWidget(self.view) self.vbox.removeWidget(self.stacked) self.vbox.removeWidget(self.line) self.view.setParent(None) self.view.hide() self.view.deleteLater() if self.toolspace: self.viewlayout.removeWidget(self.toolspace) self.toolspace.setParent(None) self.toolspace.hide() self.toolspace.deleteLater() if self.view and hasattr(self.view, "uuid"): if self.animation_manager: self.animation_manager.remove(self.view.uuid) self.view = None self.toolspace = None def setView(self, label, update=True): # If there isn't any view for this fragment, use the first available view # of this kind of fragment. if not label: assert frag_types.has_key(self.fragment.type) assert len(frag_types[self.fragment.type].views) > 0 label = frag_types[self.fragment.type].views[0] for button in self.buttons: if label in button.toolTip(): button.visible = False else: if not button.isEnabled(): button.visible = True # assert views_list.has_key(label) self.freeView() # Create the view object. self.view = views_list[label](self.fetcher, self) if label == "histo" or label == 'pie': self.view.is_graphics_view = True if label == 'histo': self.view.chart_type = BARCHART else: self.view.chart_type = PIECHART else: self.view.is_graphics_view = False if label != "error": self.connect(self, SIGNAL("closed"), self.setClosed) if self.animation_manager: if self.view.is_graphics_view: self.connect(self.view, SIGNAL("animation_done(QString)"), self, SIGNAL("animation_done(QString)")) self.animation_manager.addView(self.view) self.connect(self.view, SIGNAL("showButtons"), self.showButtonsSlot) self.connect(self.view, SIGNAL("autoRefresh"), self.updateData) self.view.setCumulative(self.cumulative_mode) self.view.setInterval(self.interval) self.stacked.insertWidget(0, self.view) self._show_view() self.connect(self.view, SIGNAL('open_page'), self._open_page) self.connect(self.view, SIGNAL('add_filter'), self._add_filter) self.connect(self.view, SIGNAL('updating'), self._show_animation) self.connect(self.view, SIGNAL('updated'), self._show_view) self.connect(self.view, SIGNAL('EAS_Message'), self.EAS_SendMessage) # Set some features if there are available on each or each type of widget. if hasattr(self.view, 'setFrameShape'): self.view.setFrameShape(QFrame.NoFrame) self.view.setContextMenuPolicy(Qt.ActionsContextMenu) # All views can ask me to display a toolspace (a widget with all kind of # things in). self.view.title.setText(self.view.getTitle()) self.fragment.view = label self.toolspace = self.view.getToolspace() self.viewlayout.insertWidget(0, self.toolspace) self.vbox.addWidget(self.line) self.vbox.addWidget(self.stacked) # Set the new menu. for action in self.actions(): self.removeAction(action) for view_label, action in self.switch_actions.items(): action.setEnabled(view_label != self.fragment.view) for action in self.action_list: self.addAction(action) self.view.addAction(action) # Add view's eventual menu. view_actions = self.view.getActions() if view_actions: separator = QAction(self) separator.setSeparator(True) view_actions = [separator] + view_actions for action in view_actions: self.view.addAction(action) self.addAction(action) if self.has_menu_pos: self.view.addAction(self.pos_menu.menuAction()) self.addAction(self.pos_menu.menuAction()) if update: self.updateData() def setClosed(self): if self.view: self.view.setClosed() self.destructor() def errorHandler(self, e): """ This method is called when fetcher raises an error. """ # Store error in fragment, and the ErrorFragmentView will able to # load it error = exceptionAsUnicode(e) self.fragment.error = error # We keep last view in the fragment, to prevent setView() method to # put 'error' in the fragment.view string attribute. last_view = self.fragment.view self.setView('error', update=False) # load the error fragment self.fragment.view = last_view def showButtonsSlot(self): for button in self.buttons: if hasattr(button, 'visible'): if button.visible: button.setEnabled(True) else: button.setEnabled(False) def updateData(self): if hasattr(self.fragment, 'error'): self.setView(self.fragment.view, update=False) del self.fragment.error for button in self.buttons: button.setEnabled(False) self.view.requestData() def _open_page(self, *args, **kwargs): self.emit(SIGNAL('open_page'), *args, **kwargs) def _add_filter(self, *args, **kwargs): self.emit(SIGNAL('add_filter'), *args, **kwargs) def EAS_SendMessage(self, *args, **kwargs): self.emit(SIGNAL('EAS_Message'), *args, **kwargs) def _show_animation(self): self.stacked.setCurrentIndex(1) def _show_view(self): self.stacked.setCurrentIndex(0)