def generateDragPixmap ( self, toolWindows ): ''' 生成一个QTabBar的快照 ''' widget = QTabBar () widget.setDocumentMode (True) for toolWindow in toolWindows: widget.addTab (toolWindow.windowIcon (), toolWindow.windowTitle ()) #if QT_VERSION >= 0x050000 # Qt5 return widget.grab ()
class App(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Web Browser") self.create_app() # self.setBaseSize(1366, 768) self.setMinimumSize(1366, 768) def create_app(self): self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) # Create Tabs self.tabbar = QTabBar(movable=True, tabsClosable=True) self.tabbar.tabCloseRequested.connect(self.close_tab) self.tabbar.addTab("New Tab") self.tabbar.addTab("+") # self.tabbar = QTabWidget() # self.tabbar.addTab(QPushButton("Tab 1"), "New Tab") # self.tabbar.addTab(QPushButton("Tab 2"), "New Tab2") self.tabbar.setCurrentIndex(0) # End Tabs # Create AddressBar self.Toolbar = QWidget() self.ToolbarLayout = QHBoxLayout() self.addressbar = AddressBar() self.Toolbar.setLayout(self.ToolbarLayout) self.ToolbarLayout.addWidget(self.addressbar) # End AddressBar # Set Main View self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) self.layout.addWidget(self.tabbar) self.layout.addWidget(self.Toolbar) self.layout.addWidget(self.container) self.setLayout(self.layout) self.show() def close_tab(self, i): self.tabbar.removeTab(i) print(i)
def _MakeTabBar(self, shap, text, icons, fancy): ''' @param: shap QTabBar::Shap @param: text bool @param: icons bool @param: fancy bool ''' bar = QTabBar(self) bar.setShape(shap) bar.setDocumentMode(True) bar.setUsesScrollButtons(True) if shap == QTabBar.RoundedWest: bar.setIconSize(QSize(22, 22)) if fancy: bar.setStyle(self._proxy_style) if shap == QTabBar.RoundedNorth: self._top_layout.insertWidget(0, bar) else: self._side_layout.insertWidget(0, bar) # Item for item in self._items: if item.type != self.Item.Type_Tab: continue label = item.tab_label if shap == QTabBar.RoundedWest: label = QFontMetrics(self.font()).elidedText( label, Qt.ElideMiddle, 100) tab_id = -1 if icons and text: tab_id = bar.addTab(item.tab_icon, label) elif icons: tab_id = bar.addTab(item.tab_icon, '') elif text: tab_id = bar.addTab(label) bar.setTabToolTip(tab_id, item.tab_label) bar.setCurrentIndex(self._stack.currentIndex()) bar.currentChanged.connect(self._ShowWidget) self._tab_bar = bar
class Example(QMainWindow): def __init__(self, parent=parent): super().__init__(self, parent) screen_resolution = app.desktop().screenGeometry() width, height = screen_resolution.width(), screen_resolution.height() self.initUI() def initUI(self): self.statusBar().showMessage('Ready') self.btn = QPushButton("Button", self) self.btn.setToolTip("Test Button") self.btn.setIcon(QIcon("/home/hsa/PycharmProjects/test12/home-6x.png")) #btn.setIconSize(QSize(24,24)) self.btn.move(50, 50) self.btn.clicked.connect(self.on_clicked) self.setGeometry(0, 0, width, height) self.setWindowTitle('MainWindow') #self.mysubwindow() def mysubwindow(self): self.mdi = QMdiArea() self.setCentralWidget(self.mdi) self.sub = QMdiSubWindow() self.sub.setGeometry(10, 10, width - 30, height - 100) self.tabbar = QTabBar() self.sub.setWidget(self.tabbar) self.tabbar.addTab("Test1") self.tabbar.addTab("Test2") self.sub.setWindowTitle("subwindow") self.mdi.addSubWindow(self.sub) self.sub.show() @pyqtSlot() def on_clicked(self): print("Button clicked")
def initUI(self): menubar = self.menuBar() mega = menubar.addMenu("&Megasena") quina = menubar.addMenu("&Quina") tabs = QTabWidget(self) tab_bar =QTabBar(tabs) tab_1 = tab_bar.addTab("Main") tab_2 = tab_bar.addTab("Description") vbox = QHBoxLayout() #vbox.addWidget(menu_bar) vbox.addWidget(tabs) self.setLayout(vbox) self.statusBar().showMessage("Working fine") self.setGeometry(300, 300, 700, 500) self.setWindowTitle('Lotericas') self.show()
class Application(QFrame): def __init__(self): super().__init__() self.setWindowIcon(QIcon("Logo.png")) self.setWindowTitle("Balongi") self.setBaseSize(1400, 720) self.setMinimumSize(1400, 720) self.CreateApplication() def CreateApplication(self): self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) #Create Tabs self.tabbar = QTabBar(movable=True, tabsClosable=True) self.tabbar.tabCloseRequested.connect(self.CloseTab) self.tabbar.tabBarClicked.connect(self.SwitchTab) self.tabbar.setCurrentIndex(0) self.tabbar.setDrawBase(False) self.tabbar.setLayoutDirection(Qt.LeftToRight) self.tabbar.setElideMode(Qt.ElideLeft) # Keep Track at Tabs self.tabCount = 0 self.tabs = [] #Create AddressBar self.Toolbar = QWidget() self.Toolbar.setObjectName("Toolbar") self.Toolbarlayout = QHBoxLayout() self.addressb = AdressB() self.AddTabButton = QPushButton("🞢") #Connect addressbar + button signals self.addressb.returnPressed.connect(self.Browse) self.AddTabButton.clicked.connect(self.AddTab) #Set toolbar buttons self.BackButton = QPushButton("🠜") self.BackButton.clicked.connect(self.GoBack) self.ForwardButton = QPushButton("🠞") self.ForwardButton.clicked.connect(self.GoForward) self.ReloadButton = QPushButton("â®") self.ReloadButton.clicked.connect(self.ReloadPage) #Build a toolbar self.Toolbar.setLayout(self.Toolbarlayout) self.Toolbarlayout.addWidget(self.BackButton) self.Toolbarlayout.addWidget(self.ForwardButton) self.Toolbarlayout.addWidget(self.ReloadButton) self.Toolbarlayout.addWidget(self.addressb) self.Toolbarlayout.addWidget(self.AddTabButton) # Set Main View self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) self.layout.addWidget(self.tabbar) self.layout.addWidget(self.Toolbar) self.layout.addWidget(self.container) self.setLayout(self.layout) self.AddTab() self.show() def CloseTab(self, i): self.tabbar.removeTab(i) def AddTab(self): i = self.tabCount self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].layout.setContentsMargins(0, 0, 0, 0) #For tab switching self.tabs[i].setObjectName("tab" + str(i)) #Open webview self.tabs[i].content = QWebEngineView() self.tabs[i].content.load(QUrl.fromUserInput("http://google.com")) self.tabs[i].content.titleChanged.connect( lambda: self.SetTabContent(i, "title")) self.tabs[i].content.iconChanged.connect( lambda: self.SetTabContent(i, "icon")) self.tabs[i].content.urlChanged.connect( lambda: self.SetTabContent(i, "url")) #Add web view to tabs layout self.tabs[i].layout.addWidget(self.tabs[i].content) # Set Top Level Tab from list to layout self.tabs[i].setLayout(self.tabs[i].layout) #Add tab to top level stackwidget self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) #Set the tabs at the top of the screen self.tabbar.addTab("New Tab") self.tabbar.setTabData(i, {"object": "tab" + str(i), "initial": i}) print("tabData: ", self.tabbar.tabData(i)["object"]) self.tabbar.setCurrentIndex(i) self.tabCount += 1 def SwitchTab(self, i): tab_data = self.tabbar.tabData(i)["object"] tab_content = self.findChild(QWidget, tab_data) self.container.layout.setCurrentWidget(tab_content) new_url = tab_content.content.url().toString() self.addressb.setText(new_url) def Browse(self): text = self.addressb.text() print(text) i = self.tabbar.currentIndex() tab = self.tabbar.tabData(i)["object"] web_view = self.findChild(QWidget, tab).content if "http" not in text: if "." not in text: url = "https://www.google.com/#q=" + text else: url = "http://" + text else: url = text web_view.load(QUrl.fromUserInput(url)) def SetTabContent(self, i, type): ''' self.tabs[i].objectName = tab1 self.tabbar.tabDat[i]["object"] = tab1 ''' tab_name = self.tabs[i].objectName() # tab1 count = 0 running = True currentTab = self.tabbar.tabData(self.tabbar.currentIndex())["object"] if currentTab == tab_name and type == "url": new_url = self.findChild(QWidget, tab_name).content.url().toString() self.addressb.setText(new_url) else: while running: tab_data_name = self.tabbar.tabData(count) if count >= 99: running = False if tab_name == tab_data_name["object"]: if type == "title": newTitle = self.findChild(QWidget, tab_name).content.title() self.tabbar.setTabText(count, newTitle) elif type == "icon": newIcon = self.findChild(QWidget, tab_name).content.icon() self.tabbar.setTabIcon(count, newIcon) running = False else: count += 1 def GoBack(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.back() def GoForward(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.forward() def ReloadPage(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.reload()
class App(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Browser") self.setBaseSize(1366, 768) self.setMinimumSize(1366, 768) self.create_app() self.setWindowIcon(QIcon("logo.png")) # noinspection PyAttributeOutsideInit def create_app(self): self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) # Create Tabs self.tabbar = QTabBar(movable=True, tabsClosable=True) self.tabbar.tabCloseRequested.connect(self.close_tab) self.tabbar.tabBarClicked.connect(self.switch_tab) self.tabbar.setCurrentIndex(0) self.tabbar.setDrawBase(False) self.tabbar.setLayoutDirection(Qt.LeftToRight) self.tabbar.setElideMode(Qt.ElideLeft) self.shortcut_new_tab = QShortcut(QKeySequence("Ctrl+T"), self) self.shortcut_new_tab.activated.connect(self.add_tab) self.shortcut_reload = QShortcut(QKeySequence("Ctrl+R"), self) self.shortcut_reload.activated.connect(self.reload_page) # Keep track of tabs self.tab_count = 0 self.tabs = [] # Create Address Bar self.toolbar = QWidget() self.toolbar.setObjectName("toolbar") self.toolbar_layout = QHBoxLayout() self.addressbar = AddressBar() self.add_tab_button = QPushButton("+") # Connect AdressBar + button Signals self.addressbar.returnPressed.connect(self.browse_to) self.add_tab_button.clicked.connect(self.add_tab) # Set toolbar buttons self.back_button = QPushButton("<") self.back_button.clicked.connect(self.go_back) self.forward_button = QPushButton(">") self.forward_button.clicked.connect(self.go_forward) self.reload_button = QPushButton("R") self.reload_button.clicked.connect(self.reload_page) # Build toolbar self.toolbar.setLayout(self.toolbar_layout) self.toolbar_layout.addWidget(self.back_button) self.toolbar_layout.addWidget(self.reload_button) self.toolbar_layout.addWidget(self.forward_button) self.toolbar_layout.addWidget(self.addressbar) self.toolbar_layout.addWidget(self.add_tab_button) # Set main view self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) self.layout.addWidget(self.tabbar) self.layout.addWidget(self.toolbar) self.layout.addWidget(self.container) self.setLayout(self.layout) self.add_tab() self.show() def close_tab(self, i): self.tabbar.removeTab(i) # noinspection PyCallByClass def add_tab(self): i = self.tab_count self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].setObjectName("tab" + str(i)) self.tabs[i].layout.setContentsMargins(0, 0, 0, 0) # Open webView self.tabs[i].content = QWebEngineView() self.tabs[i].content.load(QUrl.fromUserInput("http://google.com")) self.tabs[i].content.titleChanged.connect(lambda: self.set_tab_content(i, "title")) self.tabs[i].content.iconChanged.connect(lambda: self.set_tab_content(i, "icon")) self.tabs[i].content.urlChanged.connect(lambda: self.set_tab_content(i, "url")) # Add webView to tabs layout self.tabs[i].layout.addWidget(self.tabs[i].content) # Set top level tab from [] to layout self.tabs[i].setLayout(self.tabs[i].layout) # Add tab to top level stackedWidget self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) # Create tab on tabbar, representing this tab, # set tabData to tab# so it knows what self.tabs# it needs to control self.tabbar.addTab("New Tab") self.tabbar.setTabData(i, {"object": "tab" + str(i), "initial": i}) ''' self.tabs[i].objectName = tab1 self.tabbar.tabData(i)["object"] = tab1 ''' self.tabbar.setCurrentIndex(i) # +=1 self.tab_count += 1 def switch_tab(self, i): if self.tabbar.tabData(i): tab_data = self.tabbar.tabData(i)["object"] tab_content = self.findChild(QWidget, tab_data) self.container.layout.setCurrentWidget(tab_content) new_url = tab_content.content.url().toString() self.addressbar.setText(new_url) def browse_to(self): text = self.addressbar.text() i = self.tabbar.currentIndex() tab = self.tabbar.tabData(i)["object"] wv = self.findChild(QWidget, tab).content if "http" not in text: if "." not in text: url = "https://www.google.com/#q=" + text else: url = "https://" + text else: url = text wv.load(QUrl.fromUserInput(url)) def set_tab_content(self, i, type): tab_name = self.tabs[i].objectName() count = 0 running = True current_tab = self.tabbar.tabData(self.tabbar.currentIndex())["object"] if current_tab == tab_name and type == "url": new_url = self.findChild(QWidget, tab_name).content.url().toString() self.addressbar.setText(new_url) return False while running: tab_data_name = self.tabbar.tabData(count) if count >= 99: running = False if tab_name == tab_data_name["object"]: if type == "title": new_title = self.findChild(QWidget, tab_name).content.title() self.tabbar.setTabText(count, new_title) running = False elif type == "icon": new_icon = self.findChild(QWidget, tab_name).content.icon() self.tabbar.setTabIcon(count, new_icon) running = False else: count += 1 def go_back(self): active_index = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(active_index)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.back() def go_forward(self): active_index = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(active_index)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.forward() def reload_page(self): active_index = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(active_index)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.reload()
class App(QWidget): def __init__(self): super().__init__() self.init_ui() def okno(self): self.setGeometry(300, 300, 750, 500) self.setWindowTitle('WITCHER WITH BLACKJACK AND PLOTVA') self.setWindowIcon(QIcon('ico.ico')) def buttons(self): self.armorbox = QComboBox() self.wpnbox = QComboBox() self.mapbox = QComboBox() self.markettab = QTabBar() self.markettab.setShape(1) self.marketbox = QComboBox() self.markettab.addTab('Weapons') self.markettab.addTab('Armor') self.buybtn = QPushButton('Buy') buttons_names = [ 'Start', 'Load', 'Attack', 'Escape', 'Inventory', 'Save', 'Search for a treasure', 'Opponent', 'Map', 'Change weapon', 'Leave inventory', 'Change armor', 'Change location', 'Exit Map', 'Buy', 'Market', 'Exit Market', 'Sell garbage' ] self.buttons_dict = [ 'startbtn', 'loadbtn', 'atkbtn', 'escbtn', 'invbtn', 'savebtn', 'srbtn', 'fndbtn', 'mapbtn', 'cngwpnbtn', 'extinvbtn', 'cngarmorbtn', 'cnglocbtn', 'extmapbtn', 'buybtn', 'marketbtn', 'extmarket', 'sellbtn' ] for x, y in zip_longest(self.buttons_dict, buttons_names): exec('self.%s = QPushButton("%s")' % (x, y)) def init_ui(self): self.okno() self.grid = QGridLayout() self.setLayout(self.grid) self.label = QTextEdit() pal = QPalette() pal.setColor(QPalette.Base, QColor.fromRgb(242, 242, 242)) self.label.setPalette(pal) self.label.setReadOnly(True) self.label.setFrameStyle(QFrame.Box) # main label self.label.setFrameShadow(QFrame.Raised) self.label.setMidLineWidth(1) self.label.setLineWidth(1) self.label.setAlignment(Qt.AlignTop) self.grid.addWidget(self.label, 1, 1, 1, 2) self.label.setText('Are you ready for adventure?') self.statlabel = QLabel() self.statlabel.setFrameStyle(QFrame.Box) # stat label self.statlabel.setFrameShadow(QFrame.Raised) self.statlabel.setMidLineWidth(1) self.statlabel.setLineWidth(1) self.statlabel.setAlignment(Qt.AlignTop) self.grid.addWidget(self.statlabel, 1, 3) self.buttons() self.grid.addWidget(self.startbtn, 2, 1) # start screen self.grid.addWidget(self.loadbtn, 2, 2) self.grid.addWidget(self.srbtn, 2, 1) # main mode self.grid.addWidget(self.fndbtn, 2, 2) self.grid.addWidget(self.invbtn, 3, 1) self.grid.addWidget(self.savebtn, 3, 2) self.grid.addWidget(self.mapbtn, 4, 1) self.savebtn.hide() self.srbtn.hide() self.fndbtn.hide() self.mapbtn.hide() self.invbtn.hide() self.grid.addWidget(self.atkbtn, 2, 2) # fight mode self.grid.addWidget(self.escbtn, 2, 1) self.atkbtn.hide() self.escbtn.hide() self.grid.addWidget(self.wpnbox, 2, 1) # inventory mode self.grid.addWidget(self.extinvbtn, 4, 1) self.grid.addWidget(self.cngwpnbtn, 2, 2) self.grid.addWidget(self.armorbox, 3, 1) self.grid.addWidget(self.cngarmorbtn, 3, 2) self.armorbox.hide() self.cngarmorbtn.hide() self.cngwpnbtn.hide() self.extinvbtn.hide() self.wpnbox.hide() self.grid.addWidget(self.mapbox, 2, 1) # map mode self.grid.addWidget(self.cnglocbtn, 2, 2) self.grid.addWidget(self.extmapbtn, 3, 1) self.grid.addWidget(self.marketbtn, 3, 2) self.marketbtn.hide() self.mapbox.hide() self.extmapbtn.hide() self.cnglocbtn.hide() self.grid.addWidget(self.markettab, 2, 1) # market mode self.grid.addWidget(self.sellbtn, 4, 1) self.grid.addWidget(self.marketbox, 3, 1) self.grid.addWidget(self.buybtn, 3, 2) self.grid.addWidget(self.extmarket, 4, 2) self.buybtn.hide() self.sellbtn.hide() self.extmarket.hide() self.markettab.hide() self.marketbox.hide() self.show()
class Application(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Web Browser") self.create_app() self.setBaseSize(1024, 768) self.setMinimumSize(1024, 768) self.setWindowIcon(QIcon("logo.png")) def create_app(self): self.layout = QVBoxLayout() self.toolbar = QWidget() self.toolbar.setObjectName("toolbar") self.toolbar_layout = QHBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) self.shortcutNewTab = QShortcut(QKeySequence("Ctrl+T"), self) self.shortcutNewTab.activated.connect(self.add_tab) self.shortcutReload = QShortcut(QKeySequence("Ctrl+R"), self) self.shortcutReload.activated.connect(self.reload_page) # Create Tabs self.tab_bar = QTabBar(movable=True, tabsClosable=True) self.tab_bar.tabCloseRequested.connect(self.close_tab) self.tab_bar.tabBarClicked.connect(self.switch_tab) self.tab_bar.setCurrentIndex(0) self.tab_bar.setDrawBase(False) # Keep track of tabs self.tab_count = 0 self.tabs = [] # Add Tab Button self.AddTabButton = QPushButton("+") self.AddTabButton.clicked.connect(self.add_tab) # Create address bar self.address_bar = Address_Bar() self.address_bar.returnPressed.connect(self.browse_to) # Set Toolbar Buttons self.back_button = QPushButton("<") self.back_button.clicked.connect(self.go_back) self.forward_button = QPushButton(">") self.forward_button.clicked.connect(self.go_forward) self.reload_button = QPushButton("R") self.reload_button.clicked.connect(self.reload_page) #Build Toolbar self.toolbar.setLayout(self.toolbar_layout) self.toolbar_layout.addWidget(self.back_button) self.toolbar_layout.addWidget(self.forward_button) self.toolbar_layout.addWidget(self.reload_button) self.toolbar_layout.addWidget(self.address_bar) self.toolbar_layout.addWidget(self.AddTabButton) # Set Main View self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) self.layout.addWidget(self.tab_bar) self.layout.addWidget(self.toolbar) self.layout.addWidget(self.container) self.setLayout(self.layout) self.add_tab() self.show() def close_tab(self, i): self.tab_bar.removeTab(i) def add_tab(self): i = self.tab_count self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].layout.setContentsMargins(0, 0, 0, 0) self.tabs[i].setObjectName("tab" + str(i)) # Open Webview self.tabs[i].content = QWebEngineView() self.tabs[i].content.load(QUrl.fromUserInput("http://google.com")) self.tabs[i].content.titleChanged.connect( lambda: self.set_tab_content(i, "title")) self.tabs[i].content.iconChanged.connect( lambda: self.set_tab_content(i, "icon")) self.tabs[i].content.urlChanged.connect( lambda: self.set_tab_content(i, "url")) # Add webview to tabs layout # self.tabs[i].splitview = QSplitter() self.tabs[i].layout.addWidget(self.tabs[i].content) # self.tabs[i].splitview.addWidget(self.tabs[i].content) # Set top level tab from [] to layout self.tabs[i].setLayout(self.tabs[i].layout) # Add tab to top level stacked widget self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) # Create tab on tab bar, # Set tabData to tab<#> So it knows what self.tabs[#] it needs to control self.tab_bar.addTab("New Tab") self.tab_bar.setTabData(i, {"object": "tab" + str(i), "initial": i}) self.tab_bar.setCurrentIndex(i) self.tab_count += 1 def switch_tab(self, i): tab_data = self.tab_bar.tabData(i)["object"] tab_content = self.findChild(QWidget, tab_data) self.container.layout.setCurrentWidget(tab_content) new_url = tab_content.content.url().toString() self.address_bar.setText(new_url) def browse_to(self): text = self.address_bar.text() i = self.tab_bar.currentIndex() tab = self.tab_bar.tabData(i)["object"] web_view = self.findChild(QWidget, tab).content if "http" not in text: if "." not in text: url = "https://www.google.com/search?q=" + text else: url = "http://" + text else: url = text web_view.load(QUrl.fromUserInput(url)) def set_tab_content(self, i, type): tab_name = self.tabs[i].objectName() count = 0 running = True current_tab = self.tab_bar.tabData( self.tab_bar.currentIndex())["object"] if current_tab == tab_name and type == "url": new_url = self.findChild(QWidget, tab_name).content.url().toString() self.address_bar.setText(new_url) return False while running: tab_data_name = self.tab_bar.tabData(count) if count >= 99: running = False if tab_name == tab_data_name["object"]: if type == "title": new_title = self.findChild(QWidget, tab_name).content.title() self.tab_bar.setTabText(count, new_title) elif type == "icon": new_icon = self.findChild(QWidget, tab_name).content.icon() self.tab_bar.setTabIcon(count, new_icon) running = False else: count += 1 def go_back(self): activeIndex = self.tab_bar.currentIndex() tab_name = self.tab_bar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.back() def go_forward(self): activeIndex = self.tab_bar.currentIndex() tab_name = self.tab_bar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.forward() def reload_page(self): activeIndex = self.tab_bar.currentIndex() tab_name = self.tab_bar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.reload()
class MainWindow(QMainWindow): def __init__(self, doc): QMainWindow.__init__(self, None) self.doc = doc self.app = doc.app self._setupUi() # Create base elements self.model = MainWindowModel(document=doc.model) self.model2view = {} self.alookup = Lookup(self, model=self.model.account_lookup) self.clookup = Lookup(self, model=self.model.completion_lookup) self.drsel = DateRangeSelector(mainwindow=self, view=self.dateRangeSelectorView) self.sfield = SearchField(model=self.model.search_field, view=self.searchLineEdit) self.importWindow = ImportWindow(self) self.csvOptionsWindow = CSVOptionsWindow(self) self.recentDocuments = Recent(self.app, 'recentDocuments') self.recentDocuments.addMenu(self.menuOpenRecent) self.model.view = self self.model.connect() self._updateUndoActions() self._bindSignals() def _setupUi(self): # has to take place *before* base elements creation self.setWindowTitle("moneyGuru") self.resize(700, 580) self.centralwidget = QWidget(self) self.verticalLayout = QVBoxLayout(self.centralwidget) self.verticalLayout.setSpacing(0) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.topBar = QWidget(self.centralwidget) self.horizontalLayout_2 = QHBoxLayout(self.topBar) self.horizontalLayout_2.setContentsMargins(2, 0, 2, 0) spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem) self.dateRangeSelectorView = DateRangeSelectorView(self.topBar) self.dateRangeSelectorView.setMinimumSize(QSize(220, 0)) self.horizontalLayout_2.addWidget(self.dateRangeSelectorView) spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem1) self.searchLineEdit = SearchEdit(self.topBar) self.searchLineEdit.setMaximumSize(QSize(240, 16777215)) self.horizontalLayout_2.addWidget(self.searchLineEdit) self.verticalLayout.addWidget(self.topBar) self.tabBar = QTabBar(self.centralwidget) self.tabBar.setMinimumSize(QSize(0, 20)) self.verticalLayout.addWidget(self.tabBar) self.mainView = QStackedWidget(self.centralwidget) self.verticalLayout.addWidget(self.mainView) # Bottom buttons & status label self.bottomBar = QWidget(self.centralwidget) self.horizontalLayout = QHBoxLayout(self.bottomBar) self.horizontalLayout.setContentsMargins(2, 2, 2, 2) self.horizontalLayout.setContentsMargins(0, 0, 0, 0) self.newItemButton = QPushButton(self.bottomBar) buttonSizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) buttonSizePolicy.setHorizontalStretch(0) buttonSizePolicy.setVerticalStretch(0) buttonSizePolicy.setHeightForWidth(self.newItemButton.sizePolicy().hasHeightForWidth()) self.newItemButton.setSizePolicy(buttonSizePolicy) self.newItemButton.setIcon(QIcon(QPixmap(':/plus_8'))) self.horizontalLayout.addWidget(self.newItemButton) self.deleteItemButton = QPushButton(self.bottomBar) self.deleteItemButton.setSizePolicy(buttonSizePolicy) self.deleteItemButton.setIcon(QIcon(QPixmap(':/minus_8'))) self.horizontalLayout.addWidget(self.deleteItemButton) self.editItemButton = QPushButton(self.bottomBar) self.editItemButton.setSizePolicy(buttonSizePolicy) self.editItemButton.setIcon(QIcon(QPixmap(':/info_gray_12'))) self.horizontalLayout.addWidget(self.editItemButton) self.horizontalLayout.addItem(horizontalSpacer(size=20)) self.graphVisibilityButton = QPushButton() self.graphVisibilityButton.setSizePolicy(buttonSizePolicy) self.graphVisibilityButton.setIcon(QIcon(QPixmap(':/graph_visibility_on_16'))) self.horizontalLayout.addWidget(self.graphVisibilityButton) self.piechartVisibilityButton = QPushButton() self.piechartVisibilityButton.setSizePolicy(buttonSizePolicy) self.piechartVisibilityButton.setIcon(QIcon(QPixmap(':/piechart_visibility_on_16'))) self.horizontalLayout.addWidget(self.piechartVisibilityButton) self.columnsVisibilityButton = QPushButton() self.columnsVisibilityButton.setSizePolicy(buttonSizePolicy) self.columnsVisibilityButton.setIcon(QIcon(QPixmap(':/columns_16'))) self.horizontalLayout.addWidget(self.columnsVisibilityButton) self.statusLabel = QLabel(tr("Status")) self.statusLabel.setAlignment(Qt.AlignCenter) self.horizontalLayout.addWidget(self.statusLabel) self.verticalLayout.addWidget(self.bottomBar) self.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(self) self.menubar.setGeometry(QRect(0, 0, 700, 20)) self.menuFile = QMenu(tr("File")) self.menuOpenRecent = QMenu(tr("Open Recent")) self.menuView = QMenu(tr("View")) self.menuDateRange = QMenu(tr("Date Range")) self.menuEdit = QMenu(tr("Edit")) self.menuHelp = QMenu(tr("Help")) self.setMenuBar(self.menubar) self.actionOpenDocument = QAction(tr("Open..."), self) self.actionOpenDocument.setShortcut("Ctrl+O") self.actionShowNetWorth = QAction(tr("Net Worth"), self) self.actionShowNetWorth.setShortcut("Ctrl+1") self.actionShowNetWorth.setIcon(QIcon(QPixmap(':/balance_sheet_48'))) self.actionShowProfitLoss = QAction(escapeamp(tr("Profit & Loss")), self) self.actionShowProfitLoss.setShortcut("Ctrl+2") self.actionShowProfitLoss.setIcon(QIcon(QPixmap(':/income_statement_48'))) self.actionShowTransactions = QAction(tr("Transactions"), self) self.actionShowTransactions.setShortcut("Ctrl+3") self.actionShowTransactions.setIcon(QIcon(QPixmap(':/transaction_table_48'))) self.actionShowSelectedAccount = QAction(tr("Show Account"), self) self.actionShowSelectedAccount.setShortcut("Ctrl+]") self.actionNewItem = QAction(tr("New Item"), self) self.actionNewItem.setShortcut("Ctrl+N") self.actionDeleteItem = QAction(tr("Remove Selected"), self) self.actionEditItem = QAction(tr("Show Info"), self) self.actionEditItem.setShortcut("Ctrl+I") self.actionToggleGraph = QAction(tr("Toggle Graph"), self) self.actionToggleGraph.setShortcut("Ctrl+Alt+G") self.actionTogglePieChart = QAction(tr("Toggle Pie Chart"), self) self.actionTogglePieChart.setShortcut("Ctrl+Alt+P") self.actionMoveUp = QAction(tr("Move Up"), self) self.actionMoveUp.setShortcut("Ctrl++") self.actionMoveDown = QAction(tr("Move Down"), self) self.actionMoveDown.setShortcut("Ctrl+-") self.actionNavigateBack = QAction(tr("Go Back"), self) self.actionNavigateBack.setShortcut("Ctrl+[") self.actionNewAccountGroup = QAction(tr("New Account Group"), self) self.actionNewAccountGroup.setShortcut("Ctrl+Shift+N") self.actionShowNextView = QAction(tr("Next View"), self) self.actionShowNextView.setShortcut("Ctrl+Shift+]") self.actionShowPreviousView = QAction(tr("Previous View"), self) self.actionShowPreviousView.setShortcut("Ctrl+Shift+[") self.actionNewDocument = QAction(tr("New Document"), self) self.actionOpenExampleDocument = QAction(tr("Open Example Document"), self) self.actionOpenPluginFolder = QAction(tr("Open Plugin Folder"), self) self.actionImport = QAction(tr("Import..."), self) self.actionImport.setShortcut("Ctrl+Alt+I") self.actionExport = QAction(tr("Export..."), self) self.actionExport.setShortcut("Ctrl+Alt+E") self.actionSave = QAction(tr("Save"), self) self.actionSave.setShortcut("Ctrl+S") self.actionSaveAs = QAction(tr("Save As..."), self) self.actionSaveAs.setShortcut("Ctrl+Shift+S") self.actionAbout = QAction(tr("About moneyGuru"), self) self.actionToggleReconciliationMode = QAction(tr("Toggle Reconciliation Mode"), self) self.actionToggleReconciliationMode.setShortcut("Ctrl+Shift+R") self.actionToggleAccountExclusion = QAction(tr("Toggle Exclusion Status of Account"), self) self.actionToggleAccountExclusion.setShortcut("Ctrl+Shift+X") self.actionShowSchedules = QAction(tr("Schedules"), self) self.actionShowSchedules.setShortcut("Ctrl+4") self.actionShowSchedules.setIcon(QIcon(QPixmap(':/schedules_48'))) self.actionShowBudgets = QAction(tr("Budgets"), self) self.actionShowBudgets.setShortcut("Ctrl+5") self.actionShowBudgets.setIcon(QIcon(QPixmap(':/budget_48'))) self.actionReconcileSelected = QAction(tr("Reconcile Selection"), self) self.actionReconcileSelected.setShortcut("Ctrl+R") self.actionMakeScheduleFromSelected = QAction(tr("Make Schedule from Selected"), self) self.actionMakeScheduleFromSelected.setShortcut("Ctrl+M") self.actionShowPreferences = QAction(tr("Preferences..."), self) self.actionPrint = QAction(tr("Print..."), self) self.actionPrint.setShortcut("Ctrl+P") self.actionQuit = QAction(tr("Quit moneyGuru"), self) self.actionQuit.setShortcut("Ctrl+Q") self.actionUndo = QAction(tr("Undo"), self) self.actionUndo.setShortcut("Ctrl+Z") self.actionRedo = QAction(tr("Redo"), self) self.actionRedo.setShortcut("Ctrl+Y") self.actionShowHelp = QAction(tr("moneyGuru Help"), self) self.actionShowHelp.setShortcut("F1") self.actionCheckForUpdate = QAction(tr("Check for update"), self) self.actionOpenDebugLog = QAction(tr("Open Debug Log"), self) self.actionDuplicateTransaction = QAction(tr("Duplicate Transaction"), self) self.actionDuplicateTransaction.setShortcut("Ctrl+D") self.actionJumpToAccount = QAction(tr("Jump to Account..."), self) self.actionJumpToAccount.setShortcut("Ctrl+Shift+A") self.actionNewTab = QAction(tr("New Tab"), self) self.actionNewTab.setShortcut("Ctrl+T") self.actionCloseTab = QAction(tr("Close Tab"), self) self.actionCloseTab.setShortcut("Ctrl+W") self.menuFile.addAction(self.actionNewDocument) self.menuFile.addAction(self.actionNewTab) self.menuFile.addAction(self.actionOpenDocument) self.menuFile.addAction(self.menuOpenRecent.menuAction()) self.menuFile.addAction(self.actionOpenExampleDocument) self.menuFile.addAction(self.actionOpenPluginFolder) self.menuFile.addAction(self.actionImport) self.menuFile.addSeparator() self.menuFile.addAction(self.actionCloseTab) self.menuFile.addAction(self.actionSave) self.menuFile.addAction(self.actionSaveAs) self.menuFile.addAction(self.actionExport) self.menuFile.addAction(self.actionPrint) self.menuFile.addAction(self.actionQuit) self.menuView.addAction(self.actionShowNetWorth) self.menuView.addAction(self.actionShowProfitLoss) self.menuView.addAction(self.actionShowTransactions) self.menuView.addAction(self.actionShowSchedules) self.menuView.addAction(self.actionShowBudgets) self.menuView.addAction(self.actionShowPreviousView) self.menuView.addAction(self.actionShowNextView) self.menuView.addAction(self.menuDateRange.menuAction()) self.menuView.addAction(self.actionShowPreferences) self.menuView.addAction(self.actionToggleGraph) self.menuView.addAction(self.actionTogglePieChart) self.menuEdit.addAction(self.actionNewItem) self.menuEdit.addAction(self.actionNewAccountGroup) self.menuEdit.addAction(self.actionDeleteItem) self.menuEdit.addAction(self.actionEditItem) self.menuEdit.addSeparator() self.menuEdit.addAction(self.actionMoveUp) self.menuEdit.addAction(self.actionMoveDown) self.menuEdit.addAction(self.actionDuplicateTransaction) self.menuEdit.addAction(self.actionMakeScheduleFromSelected) self.menuEdit.addAction(self.actionReconcileSelected) self.menuEdit.addAction(self.actionToggleReconciliationMode) self.menuEdit.addAction(self.actionToggleAccountExclusion) self.menuEdit.addSeparator() self.menuEdit.addAction(self.actionShowSelectedAccount) self.menuEdit.addAction(self.actionNavigateBack) self.menuEdit.addAction(self.actionJumpToAccount) self.menuEdit.addSeparator() self.menuEdit.addAction(self.actionUndo) self.menuEdit.addAction(self.actionRedo) self.menuHelp.addAction(self.actionShowHelp) self.menuHelp.addAction(self.actionCheckForUpdate) self.menuHelp.addAction(self.actionOpenDebugLog) self.menuHelp.addAction(self.actionAbout) mainmenus = [self.menuFile, self.menuEdit, self.menuView, self.menuHelp] for menu in mainmenus: self.menubar.addAction(menu.menuAction()) setAccelKeys(menu) setAccelKeys(self.menubar) self.tabBar.setMovable(True) self.tabBar.setTabsClosable(True) self.tabBar.setExpanding(False) seq = QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Right) self._shortcutNextTab = QShortcut(seq, self) seq = QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Left) self._shortcutPrevTab = QShortcut(seq, self) # Linux setup if ISLINUX: self.actionCheckForUpdate.setVisible(False) # This only works on Windows def _bindSignals(self): self.newItemButton.clicked.connect(self.actionNewItem.trigger) self.deleteItemButton.clicked.connect(self.actionDeleteItem.trigger) self.editItemButton.clicked.connect(self.actionEditItem.trigger) self.graphVisibilityButton.clicked.connect(self.actionToggleGraph.trigger) self.piechartVisibilityButton.clicked.connect(self.actionTogglePieChart.trigger) self.columnsVisibilityButton.clicked.connect(self.columnsVisibilityButtonClicked) self.recentDocuments.mustOpenItem.connect(self.doc.open) self.doc.documentOpened.connect(self.recentDocuments.insertItem) self.doc.documentSavedAs.connect(self.recentDocuments.insertItem) self.doc.documentPathChanged.connect(self.documentPathChanged) self.tabBar.currentChanged.connect(self.currentTabChanged) self.tabBar.tabCloseRequested.connect(self.tabCloseRequested) self.tabBar.tabMoved.connect(self.tabMoved) # Views self.actionShowNetWorth.triggered.connect(self.showNetWorthTriggered) self.actionShowProfitLoss.triggered.connect(self.showProfitLossTriggered) self.actionShowTransactions.triggered.connect(self.showTransactionsTriggered) self.actionShowSchedules.triggered.connect(self.showSchedulesTriggered) self.actionShowBudgets.triggered.connect(self.showBudgetsTriggered) self.actionShowPreviousView.triggered.connect(self.showPreviousViewTriggered) self.actionShowNextView.triggered.connect(self.showNextViewTriggered) self.actionShowPreferences.triggered.connect(self.app.showPreferences) self.actionToggleGraph.triggered.connect(self.toggleGraphTriggered) self.actionTogglePieChart.triggered.connect(self.togglePieChartTriggered) # Document Edition self.actionNewItem.triggered.connect(self.newItemTriggered) self.actionNewAccountGroup.triggered.connect(self.newAccountGroupTriggered) self.actionDeleteItem.triggered.connect(self.deleteItemTriggered) self.actionEditItem.triggered.connect(self.editItemTriggered) self.actionMoveUp.triggered.connect(self.moveUpTriggered) self.actionMoveDown.triggered.connect(self.moveDownTriggered) self.actionDuplicateTransaction.triggered.connect(self.model.duplicate_item) self.actionUndo.triggered.connect(self.doc.model.undo) self.actionRedo.triggered.connect(self.doc.model.redo) # Open / Save / Import / Export / New self.actionNewDocument.triggered.connect(self.doc.new) self.actionOpenDocument.triggered.connect(self.doc.openDocument) self.actionOpenExampleDocument.triggered.connect(self.doc.openExampleDocument) self.actionOpenPluginFolder.triggered.connect(self.model.app.open_plugin_folder) self.actionImport.triggered.connect(self.importDocument) self.actionSave.triggered.connect(self.doc.save) self.actionSaveAs.triggered.connect(self.doc.saveAs) self.actionExport.triggered.connect(self.model.export) # Misc self.actionNewTab.triggered.connect(self.model.new_tab) self.actionCloseTab.triggered.connect(self.closeTabTriggered) self.actionShowSelectedAccount.triggered.connect(self.model.show_account) self.actionNavigateBack.triggered.connect(self.navigateBackTriggered) self.actionJumpToAccount.triggered.connect(self.jumpToAccountTriggered) self.actionMakeScheduleFromSelected.triggered.connect(self.makeScheduleFromSelectedTriggered) self.actionReconcileSelected.triggered.connect(self.reconcileSelectedTriggered) self.actionToggleReconciliationMode.triggered.connect(self.toggleReconciliationModeTriggered) self.actionToggleAccountExclusion.triggered.connect(self.toggleAccountExclusionTriggered) self.actionPrint.triggered.connect(self._print) self.actionShowHelp.triggered.connect(self.app.showHelp) self.actionCheckForUpdate.triggered.connect(self.checkForUpdateTriggered) self.actionAbout.triggered.connect(self.aboutTriggered) self.actionOpenDebugLog.triggered.connect(self.openDebugLogTriggered) self.actionQuit.triggered.connect(self.close) # Extra Shortcuts self._shortcutNextTab.activated.connect(self.showNextViewTriggered) self._shortcutPrevTab.activated.connect(self.showPreviousViewTriggered) # --- QWidget overrides def closeEvent(self, event): if self.doc.confirmDestructiveAction(): event.accept() else: event.ignore() # --- Private def _print(self): dialog = QPrintDialog(self) if dialog.exec_() != QPrintDialog.Accepted: return printer = dialog.printer() currentView = self.mainView.currentWidget() viewPrinter = ViewPrinter(printer, currentView) currentView.fitViewsForPrint(viewPrinter) viewPrinter.render() def _getViewforPane(self, pane_type, pane_view): if pane_view in self.model2view: view = self.model2view[pane_view] else: view = PANETYPE2VIEWCLASS[pane_type](model=pane_view, mainwindow=self) self.model2view[pane_view] = view self.mainView.addWidget(view) view.restoreSubviewsSize() return view def _setTabIndex(self, index): if not self.tabBar.count(): return self.tabBar.setCurrentIndex(index) self._updateActionsState() pane_type = self.model.pane_type(index) pane_view = self.model.pane_view(index) view = self._getViewforPane(pane_type, pane_view) self.mainView.setCurrentWidget(view) view.setFocus() def _activeView(self): paneIndex = self.model.current_pane_index return self.model.pane_view(paneIndex) def _updateActionsState(self): # Updates enable/disable checked/unchecked state of all actions. These state can change # under various conditions: main view change, date range type change and when reconciliation # mode is toggled # Determine what actions are enabled view = self._activeView() viewType = view.VIEW_TYPE isSheet = viewType in {PaneType.NetWorth, PaneType.Profit} isTransactionOrEntryTable = viewType in {PaneType.Transaction, PaneType.Account} canToggleReconciliation = viewType == PaneType.Account and view.can_toggle_reconciliation_mode newItemLabel = { PaneType.NetWorth: tr("New Account"), PaneType.Profit: tr("New Account"), PaneType.Transaction: tr("New Transaction"), PaneType.Account: tr("New Transaction"), PaneType.Schedule: tr("New Schedule"), PaneType.Budget: tr("New Budget"), PaneType.GeneralLedger: tr("New Transaction"), }.get(viewType, tr("New Item")) # XXX make "New Item" disabled self.actionNewItem.setText(newItemLabel) self.actionNewAccountGroup.setEnabled(isSheet) self.actionMoveDown.setEnabled(isTransactionOrEntryTable) self.actionMoveUp.setEnabled(isTransactionOrEntryTable) self.actionDuplicateTransaction.setEnabled(isTransactionOrEntryTable) self.actionMakeScheduleFromSelected.setEnabled(isTransactionOrEntryTable) self.actionReconcileSelected.setEnabled(viewType == PaneType.Account and view.reconciliation_mode) self.actionShowNextView.setEnabled(self.model.current_pane_index < self.model.pane_count-1) self.actionShowPreviousView.setEnabled(self.model.current_pane_index > 0) self.actionShowSelectedAccount.setEnabled(isSheet or isTransactionOrEntryTable) self.actionNavigateBack.setEnabled(viewType == PaneType.Account) self.actionToggleReconciliationMode.setEnabled(canToggleReconciliation) self.actionToggleAccountExclusion.setEnabled(isSheet) def _updateUndoActions(self): if self.doc.model.can_undo(): self.actionUndo.setEnabled(True) self.actionUndo.setText(tr("Undo {0}").format(self.doc.model.undo_description())) else: self.actionUndo.setEnabled(False) self.actionUndo.setText(tr("Undo")) if self.doc.model.can_redo(): self.actionRedo.setEnabled(True) self.actionRedo.setText(tr("Redo {0}").format(self.doc.model.redo_description())) else: self.actionRedo.setEnabled(False) self.actionRedo.setText(tr("Redo")) # --- Actions # Views def showNetWorthTriggered(self): self.model.select_pane_of_type(PaneType.NetWorth) def showProfitLossTriggered(self): self.model.select_pane_of_type(PaneType.Profit) def showTransactionsTriggered(self): self.model.select_pane_of_type(PaneType.Transaction) def showSchedulesTriggered(self): self.model.select_pane_of_type(PaneType.Schedule) def showBudgetsTriggered(self): self.model.select_pane_of_type(PaneType.Budget) def showPreviousViewTriggered(self): self.model.select_previous_view() def showNextViewTriggered(self): self.model.select_next_view() # Document Edition def newItemTriggered(self): self.model.new_item() def newAccountGroupTriggered(self): self.model.new_group() def deleteItemTriggered(self): self.model.delete_item() def editItemTriggered(self): self.model.edit_item() def moveUpTriggered(self): self.model.move_up() def moveDownTriggered(self): self.model.move_down() # Misc def closeTabTriggered(self): self.model.close_pane(self.model.current_pane_index) def navigateBackTriggered(self): self.model.navigate_back() def jumpToAccountTriggered(self): self.model.jump_to_account() def makeScheduleFromSelectedTriggered(self): self.model.make_schedule_from_selected() def reconcileSelectedTriggered(self): self._activeView().etable.toggle_reconciled() def toggleReconciliationModeTriggered(self): self._activeView().toggle_reconciliation_mode() self._updateActionsState() def toggleAccountExclusionTriggered(self): viewType = self.model.pane_type(self.model.current_pane_index) if viewType in {PaneType.NetWorth, PaneType.Profit}: self._activeView().sheet.toggle_excluded() def toggleGraphTriggered(self): self.model.toggle_area_visibility(PaneArea.BottomGraph) def togglePieChartTriggered(self): self.model.toggle_area_visibility(PaneArea.RightChart) def columnsVisibilityButtonClicked(self): items = self.model.column_menu_items() if not items: return menu = QMenu() for i, (display, marked) in enumerate(items): action = menu.addAction(display) action.setCheckable(True) action.setChecked(marked) action.setData(i) action.triggered.connect(self.columnsMenuItemWasClicked) self._columnMenuHolder = menu # we need to hold a reference to it while it popups button = self.columnsVisibilityButton menu.popup(button.parentWidget().mapToGlobal(button.geometry().topLeft())) def columnsMenuItemWasClicked(self): action = self.sender() if action is not None: index = action.data() self.model.toggle_column_menu_item(index) def checkForUpdateTriggered(self): QProcess.execute('updater.exe', ['/checknow']) def aboutTriggered(self): self.app.showAboutBox() def openDebugLogTriggered(self): debugLogPath = op.join(getAppData(), 'debug.log') url = QUrl.fromLocalFile(debugLogPath) QDesktopServices.openUrl(url) def importDocument(self): title = tr("Select a document to import") filters = tr("Supported files (*.moneyguru *.ofx *.qfx *.qif *.csv *.txt)") docpath, filetype = QFileDialog.getOpenFileName(self.app.mainWindow, title, '', filters) # There's a strange glitch under GNOME where, right after the dialog is gone, the main # window isn't the active window, but it will become active if we give it enough time. If we # start showing the import window before that happens, we'll end up with an import window # under the main window, which is bad. Therefore, we process events until this happens. We # do this in a big forloop instead of a while to avoid a possible infinite loop. for i in range(10000): if self.app.mainWindow.isActiveWindow(): break QApplication.processEvents() if docpath: try: self.model.parse_file_for_import(docpath) except FileFormatError as e: QMessageBox.warning(self.app.mainWindow, tr("Cannot import file"), str(e)) # --- Other Signals def currentTabChanged(self, index): self.model.current_pane_index = index self._setTabIndex(index) def documentPathChanged(self): if self.doc.documentPath: title = "moneyGuru ({})".format(self.doc.documentPath) else: title = "moneyGuru" self.setWindowTitle(title) def tabCloseRequested(self, index): self.model.close_pane(index) def tabMoved(self, fromIndex, toIndex): # We don't refresh panes because tabMoved is apparently now called *during* drag operations. # If we start a full pane refresh during a drag operation, we segfault. self.model.move_pane(fromIndex, toIndex, refresh_panes=False) # --- model --> view def change_current_pane(self): self._setTabIndex(self.model.current_pane_index) def get_panel_view(self, model): if isinstance(model, CustomDateRangePanelModel): return CustomDateRangePanel(model, self) else: return ExportPanel(model, self) def refresh_panes(self): # Always remove the "new tab" tab if self.tabBar.count() > 0: self.tabBar.removeTab(self.tabBar.count()-1) while self.tabBar.count() < self.model.pane_count: self.tabBar.addTab('') for i in range(self.model.pane_count): pane_label = self.model.pane_label(i) pane_label = escapeamp(pane_label) self.tabBar.setTabText(i, pane_label) pane_type = self.model.pane_type(i) pane_view = self.model.pane_view(i) # Ensure that the view's "view" has been created and bound self._getViewforPane(pane_type, pane_view) iconname = PANETYPE2ICON.get(pane_type) icon = QIcon(QPixmap(':/{0}'.format(iconname))) if iconname else QIcon() self.tabBar.setTabIcon(i, icon) # It's important that we proceed with tab removal *after* we've completed tab initialization. # We're walking on eggshells here. refresh_panes() can be called in multiple situations, one # of them is during the opening of a document. When that happens when another document was # previously opened, all views' model are uninitalized and don't have their "view" attribute # set yet. If we proceed with the setCurrentIndex() call below before _getViewforPane() # could be called above, we get a crash. if self.tabBar.currentIndex() >= self.model.pane_count: # Normally, we don't touch the tabBar index here and wait for change_current_pane, # but when we remove tabs, it's possible that currentTabChanged end up being called and # then the tab selection is bugged. I tried disconnecting/reconnecting the signal, but # this is buggy. So when a selected tab is about to be removed and is out of bounds, # we change the selection to the last index in the model. We don't use # self.model.current_pane_index because in some cases, it's -1 and prevents this crash # preventer from preventing its crash. self.tabBar.setCurrentIndex(self.model.pane_count - 1) while self.tabBar.count() > self.model.pane_count: self.tabBar.removeTab(self.tabBar.count()-1) self.tabBar.setTabsClosable(self.model.pane_count > 1) # Add the "new tab" tab last_tab_index = self.tabBar.addTab('') self.tabBar.setTabEnabled(last_tab_index, False) newTabButton = QToolButton() newTabButton.setText("+") newTabButton.clicked.connect(self.model.new_tab) self.tabBar.setTabButton(last_tab_index, QTabBar.RightSide, newTabButton) def refresh_status_line(self): self.statusLabel.setText(self.model.status_line) def refresh_undo_actions(self): self._updateUndoActions() def restore_window_frame(self, frame): self.setGeometry(*frame) def save_window_frame(self): r = self.geometry() return (r.x(), r.y(), r.width(), r.height()) def show_message(self, msg): title = tr("Warning") QMessageBox.warning(self, title, msg) def update_area_visibility(self): hidden = self.model.hidden_areas graphimg = ':/graph_visibility_{}_16'.format('off' if PaneArea.BottomGraph in hidden else 'on') pieimg = ':/piechart_visibility_{}_16'.format('off' if PaneArea.RightChart in hidden else 'on') self.graphVisibilityButton.setIcon(QIcon(QPixmap(graphimg))) self.piechartVisibilityButton.setIcon(QIcon(QPixmap(pieimg))) def view_closed(self, index): self.tabBar.removeTab(index) self.tabBar.setTabsClosable(self.model.pane_count > 1)
class App(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Web Browser by RafaelxFernandes") self.setBaseSize(1366, 768) self.create_app() def create_app(self): self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) # Create tabs self.tab_bar = QTabBar(movable=True, tabsClosable=True) self.tab_bar.tabCloseRequested.connect(self.close_tab) self.tab_bar.tabBarClicked.connect(self.switch_tab) self.tab_bar.setDrawBase(False) # Keep track of tabs self.tab_count = 0 self.tabs = [] # Set toolbar buttons # Back self.back_button = QPushButton("<") self.back_button.clicked.connect(self.go_back) # Forward self.forward_button = QPushButton(">") self.forward_button.clicked.connect(self.go_forward) # Reload self.reload_button = QPushButton("⟲") self.reload_button.clicked.connect(self.reload) # Create address bar self.tool_bar = QWidget() self.tool_bar.setObjectName("Toolbar") self.tool_bar_layout = QHBoxLayout() self.tool_bar.setLayout(self.tool_bar_layout) self.address_bar = AddressBar() self.address_bar.returnPressed.connect(self.browse_to) # New tab button self.add_tab_button = QPushButton("+") self.add_tab_button.clicked.connect(self.add_tab) # Build tool bar self.tool_bar_layout.addWidget(self.back_button) self.tool_bar_layout.addWidget(self.forward_button) self.tool_bar_layout.addWidget(self.reload_button) self.tool_bar_layout.addWidget(self.address_bar) self.tool_bar_layout.addWidget(self.add_tab_button) # Set main view self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) self.layout.addWidget(self.tab_bar) self.layout.addWidget(self.tool_bar) self.layout.addWidget(self.container) # Shortcuts # New tab self.shortcut_new_tab = QShortcut(QKeySequence("Ctrl+T"), self) self.shortcut_new_tab.activated.connect(self.add_tab) # Reload self.shortcut_reload = QShortcut(QKeySequence("Ctrl+R"), self) self.shortcut_reload.activated.connect(self.reload) self.setLayout(self.layout) self.add_tab() self.show() def close_tab(self, index): # print(index) self.tab_bar.removeTab(index) def add_tab(self): index = self.tab_count # Set self.tabs<#> = QWidget self.tabs.append(QWidget()) self.tabs[index].layout = QVBoxLayout() self.tabs[index].layout.setContentsMargins(0, 0, 0, 0) # For tab switching self.tabs[index].setObjectName("Tab" + str(index)) # Create webview within the tabs top level widget self.tabs[index].content = QWebEngineView() self.tabs[index].content.load(QUrl.fromUserInput("http://google.com")) self.tabs[index].content.titleChanged.connect( lambda: self.set_tab_content(index, "title")) self.tabs[index].content.iconChanged.connect( lambda: self.set_tab_content(index, "icon")) self.tabs[index].content.urlChanged.connect( lambda: self.set_tab_content(index, "url")) # Add webview to tab.layout self.tabs[index].layout.addWidget(self.tabs[index].content) # Set tab_layout to layout self.tabs[index].setLayout(self.tabs[index].layout) # Add and set new tabs content to stack widget self.container.layout.addWidget(self.tabs[index]) self.container.layout.setCurrentWidget(self.tabs[index]) # Create tab on tab_bar, representing this tab, # Set tab_data to tab<#> so it knows what self.tabs[#] it needs to control self.tab_bar.addTab("New Tab") self.tab_bar.setTabData(index, { "object": "Tab" + str(index), "initial": index }) self.tab_bar.setCurrentIndex(index) self.tab_count += 1 def switch_tab(self, index): if (self.tab_bar.tabData(index)): tab_data = self.tab_bar.tabData(index)["object"] # print("Tab: " + str(tab_data)) tab_widget = self.findChild(QWidget, tab_data) self.container.layout.setCurrentWidget(tab_widget) new_url = tab_widget.content.url().toString() self.address_bar.setText(new_url) def browse_to(self): text = self.address_bar.text() index = self.tab_bar.currentIndex() tab = self.tab_bar.tabData(index)["object"] window_view = self.findChild(QWidget, tab).content if ("http" not in text): if ("." not in text): url = "https://www.google.com/search?q=" + text else: url = "http://" + text else: url = text window_view.load(QUrl.fromUserInput(url)) def set_tab_content(self, index, type): tab_object_name = self.tabs[index].objectName() count = 0 running = True current_tab = self.tab_bar.tabData( self.tab_bar.currentIndex())["object"] if (current_tab == tab_object_name and type == "url"): new_url = self.findChild(QWidget, tab_object_name).content.url().toString() self.address_bar.setText(new_url) return False while running: tab_data_name = self.tab_bar.tabData(count) if (count >= 99): running = False if (tab_object_name == tab_data_name["object"]): if (type == "title"): new_title = self.findChild( QWidget, tab_object_name).content.title() self.tab_bar.setTabText(count, new_title) elif (type == "icon"): new_icon = self.findChild(QWidget, tab_object_name).content.icon() self.tab_bar.setTabIcon(count, new_icon) running = False else: count += 1 def go_back(self): activate_index = self.tab_bar.currentIndex() tab_name = self.tab_bar.tabData(activate_index)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.back() def go_forward(self): activate_index = self.tab_bar.currentIndex() tab_name = self.tab_bar.tabData(activate_index)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.forward() def reload(self): activate_index = self.tab_bar.currentIndex() tab_name = self.tab_bar.tabData(activate_index)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.reload()
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 App(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Python QT Web Browser") self.setMinimumSize(1920, 1200) self.CreateApp() self.setWindowIcon(QIcon("resources/icons/PyQt.jpg")) def CreateApp(self): self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) # Create Tabs self.tabbar = QTabBar(movable=True, tabsClosable=True) self.tabbar.tabCloseRequested.connect(self.CloseTab) self.tabbar.tabBarClicked.connect(self.SwitchTab) self.tabbar.setCurrentIndex(0) self.tabbar.setDrawBase(False) self.tabbar.setLayoutDirection(Qt.LeftToRight) self.tabbar.setElideMode(Qt.ElideLeft) self.shortcutNewTab = QShortcut(QKeySequence("Ctrl+T"), self) self.shortcutNewTab.activated.connect(self.AddTab) self.shortcutReload = QShortcut(QKeySequence("Ctrl+R"), self) self.shortcutReload.activated.connect(self.ReloadPage) # Keep track of the tabs self.tabCount = 0 self.tabs = [] # Create AddressBar self.Toolbar = QWidget() self.Toolbar.setObjectName("Toolbar") self.ToolbarLayout = QHBoxLayout() self.addressbar = AddressBar() self.AddTabButton = QPushButton("+") # Connect AddressBar + button Signals self.addressbar.returnPressed.connect(self.BrowseTo) self.AddTabButton.clicked.connect(self.AddTab) # Set Toolbar Buttons self.BackButton = QPushButton("<") self.BackButton.clicked.connect(self.GoBack) self.ForwardButton = QPushButton(">") self.ForwardButton.clicked.connect(self.GoForward) self.ReloadButton = QPushButton("R") self.ReloadButton.clicked.connect(self.ReloadPage) # Build toolbar self.Toolbar.setLayout(self.ToolbarLayout) self.ToolbarLayout.addWidget(self.BackButton) self.ToolbarLayout.addWidget(self.ForwardButton) self.ToolbarLayout.addWidget(self.ReloadButton) self.ToolbarLayout.addWidget(self.addressbar) self.ToolbarLayout.addWidget(self.AddTabButton) # Set main view self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) # Construct main view from top level elements self.layout.addWidget(self.tabbar) self.layout.addWidget(self.Toolbar) self.layout.addWidget(self.container) self.setLayout(self.layout) self.AddTab() self.show() def CloseTab(self, i): self.tabbar.removeTab(i) def AddTab(self): i = self.tabCount self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].layout.setContentsMargins(0, 0, 0, 0) # For tab switching self.tabs[i].setObjectName("tab" + str(i)) # Create webview within the tabs top level widget self.tabs[i].content = QWebEngineView() self.tabs[i].content.load(QUrl.fromUserInput("https://www.google.ie/")) # Add widget to tab.layout. self.tabs[i].content.titleChanged.connect( lambda: self.SetTabContent(i, "title")) self.tabs[i].content.iconChanged.connect( lambda: self.SetTabContent(i, "icon")) self.tabs[i].content.urlChanged.connect( lambda: self.SetTabContent(i, "url")) # Add webview to tabs layout self.tabs[i].splitview = QSplitter() self.tabs[i].layout.addWidget(self.tabs[i].splitview) self.tabs[i].splitview.addWidget(self.tabs[i].content) # set top level tab from [] to layout self.tabs[i].setLayout(self.tabs[i].layout) # Add tabe to top level stackedwidget self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) # Set the tab at the top of the screen self.tabbar.addTab("New Tab") self.tabbar.setTabData(i, {"object": "tab" + str(i), "initial": i}) self.tabbar.setCurrentIndex(i) self.tabCount += 1 def SwitchTab(self, i): # Switch to tab if self.tabbar.tabData(i): tab_data = self.tabbar.tabData(i)["object"] tab_content = self.findChild(QWidget, tab_data) self.container.layout.setCurrentWidget(tab_content) new_url = tab_content.content.url().toString() self.addressbar.setText(new_url) def BrowseTo(self): text = self.addressbar.text() print(text) i = self.tabbar.currentIndex() tab = self.tabbar.tabData(i)["object"] wv = self.findChild(QWidget, tab).content if "http" not in text: if "." not in text: url = "https://www.google.ie/#q=" + text else: url = "http://" + text else: url = text wv.load(QUrl.fromUserInput(url)) def SetTabContent(self, i, type): tab_name = self.tabs[i].objectName() # tab1 count = 0 running = True current_tab = self.tabbar.tabData(self.tabbar.currentIndex())["object"] if current_tab == tab_name and type == "url": new_url = self.findChild(QWidget, tab_name).content.url().toString() self.addressbar.setText(new_url) return False while running: tab_data_name = self.tabbar.tabData(count) if count >= 99: running = False if tab_name == tab_data_name["object"]: if type == "title": newTitle = self.findChild(QWidget, tab_name).content.title() self.tabbar.setTabText(count, newTitle) elif type == "icon": newIcon = self.findChild(QWidget, tab_name).content.icon() self.tabbar.setTabIcon(count, newIcon) running = False else: count += 1 def GoBack(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.back() def GoForward(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.forward() def ReloadPage(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.reload()
class FMWTabs(QWidget): """GUI for tabs and associated widgets """ tab_names = ['LCLS1', 'LCLS1->LCLS2'] tool_tips = [\ 'LCLS1 - easy access to calibration constants\nin the <experiment>/calib directory', 'Upploader of LCLS calibratiuon constants\nto LCLS2 calibration DB',\ ] def __init__(self, parent=None, app=None): QWidget.__init__(self, parent) cp.fmwtabs = self self.box_layout = QHBoxLayout() start_tab_name = cp.fmwtab_tab_name.value() self.gui_win = None self.make_tab_bar(start_tab_name) self.gui_selector(start_tab_name) self.box = QVBoxLayout(self) self.box.addWidget(self.tab_bar) self.box.addLayout(self.box_layout) self.setLayout(self.box) self.set_tool_tips() self.set_style() def set_tool_tips(self): for t, s in zip(self.tab_names, self.tool_tips): self.tab_bar.setTabToolTip(self.tab_names.index(t), s) #self.setToolTip('Main tab window') def set_style(self): from psana.graphqt.Styles import style from psana.graphqt.QWIcons import icon icon.set_icons() self.setWindowIcon(icon.icon_monitor) self.setStyleSheet(style.styleBkgd) self.layout().setContentsMargins(0, 0, 0, 0) def make_tab_bar(self, start_tab_name): self.tab_bar = QTabBar() for tab_name in self.tab_names: tab_ind = self.tab_bar.addTab(tab_name) self.tab_bar.setTabTextColor(tab_ind, QColor('blue')) #gray, red, grayblue self.tab_bar.setShape(QTabBar.RoundedNorth) tab_index = self.tab_names.index(start_tab_name) self.tab_bar.setCurrentIndex(tab_index) logger.debug('make_tab_bar - set tab index: %d' % tab_index) self.tab_bar.currentChanged['int'].connect(self.on_tab_bar) self.tab_bar.tabCloseRequested.connect(self.on_tab_close_request) self.tab_bar.tabMoved[int, int].connect(self.on_tab_moved) def gui_selector(self, tab_name): if self.gui_win is not None: self.gui_win.close() del self.gui_win w_height = 200 #if cp.cmwmain is not None: cp.cmwmain.wlog.setVisible(True) if tab_name == 'LCLS1->LCLS2': self.gui_win = QTextEdit('Selected tab "%s"' % tab_name) w_height = 400 elif tab_name == 'LCLS1': from psana.graphqt.FMW1Main import FMW1Main self.gui_win = FMW1Main() elif tab_name == 'LCLS2': self.gui_win = QTextEdit('Selected tab "%s"' % tab_name) else: self.gui_win = QTextEdit('Selected tab "%s"' % tab_name) #self.gui_win.setMinimumHeight(w_height) self.gui_win.setVisible(True) self.box_layout.addWidget(self.gui_win) def current_tab_index_and_name(self): tab_ind = self.tab_bar.currentIndex() tab_name = str(self.tab_bar.tabText(tab_ind)) return tab_ind, tab_name def on_tab_bar(self, ind): tab_ind, tab_name = self.current_tab_index_and_name() logger.info('Selected tab "%s"' % tab_name) cp.fmwtab_tab_name.setValue(tab_name) self.gui_selector(tab_name) def on_tab_close_request(self, ind): logger.debug('on_tab_close_request ind:%d' % ind) #self.tab_bar.removeTab(ind) #logger.debug('on_tab_close_request tab index:%d' % (itab)) def on_tab_moved(self, inew, iold): logger.debug('on_tab_close_request tab index begin:%d -> end:%d' % (iold, inew)) def closeEvent(self, e): logger.debug('closeEvent') if self.gui_win is not None: self.gui_win.close() QWidget.closeEvent(self, e) cp.fmwtabs = None def onExit(self): logger.debug('onExit') self.close() def set_tabs_visible(self, is_visible): logger.debug('set_tabs_visible: is_visible %s' % is_visible) self.tab_bar.setVisible(is_visible) def tab_bar_is_visible(self): return self.tab_bar.isVisible() def view_hide_tabs(self): self.tab_bar.setVisible(not self.tab_bar.isVisible()) if __name__ == "__main__": def keyPressEvent(self, e): logger.debug('keyPressEvent, key=%s' % e.key()) if e.key() == Qt.Key_Escape: self.close() elif e.key() == Qt.Key_V: self.view_hide_tabs() else: logger.debug('Keys:'\ '\n V - view/hide tabs'\ '\n')
class App(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Web Browser") self.CreateApp() self.setMaximumSize(1366, 768) def CreateApp(self): self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) # Create Tabs self.tabbar = QTabBar(movable=True, tabsClosable=True) self.tabbar.tabCloseRequested.connect(self.CloseTab) self.tabbar.tabBarClicked.connect(self.SwitchTab) # self.tabbar.addTab("Tab 1") # self.tabbar.addTab("Tab 2") self.tabbar.setCurrentIndex(0) # Keep Track Of Tabs self.tabCount = 0 self.tabs = [] # Create Address Bar self.Toolbar = QWidget() self.ToolbarLayout = QHBoxLayout() self.addressbar = AddressBar() self.Toolbar.setLayout(self.ToolbarLayout) self.ToolbarLayout.addWidget(self.addressbar) self.AddTabButton = QPushButton("+") self.addressbar.returnPressed.connect(self.BrowseTo) self.AddTabButton.clicked.connect(self.AddTab) self.ToolbarLayout.addWidget(self.AddTabButton) self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) self.layout.addWidget(self.tabbar) self.layout.addWidget(self.Toolbar) self.layout.addWidget(self.container) self.setLayout(self.layout) self.AddTab() self.show() def CloseTab(self, i): self.tabbar.removeTab(i) def AddTab(self): i = self.tabCount # set self.tabs<#> = Qwidget self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].layout.setContentsMargins(0, 0, 0, 0) # For Tab Switching self.tabs[i].setObjectName("tab" + str(i)) # Create WebView within the tabs top level widget self.tabs[i].content = QWebEngineView() self.tabs[i].content.load(QUrl.fromUserInput("https://google.com")) self.tabs[i].content.titleChanged.connect( lambda: self.setTabContent(i, "title")) self.tabs[i].content.iconChanged.connect( lambda: self.setTabContent(i, "icon")) # add widget to tab.layout self.tabs[i].layout.addWidget(self.tabs[i].content) # Add tabLayout to .layout self.tabs[i].setLayout(self.tabs[i].layout) # Add and Set new Tabs content to the stack widget self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) # create tab on tabbar, repreasenting this tab # set tabData to tab<#> So it knows what self.tabs[#] it needs to control self.tabbar.addTab("New Tab") self.tabbar.setTabData(i, {object: "tab" + str(i), "initial": i}) self.tabbar.setCurrentIndex(i) self.tabCount += 1 def SwitchTab(self, i): tab_data = self.tabbar.tabData(i) tab_content = self.findChild(QWidget, tab_data) self.container.layout.setCurrentWidget(tab_content) def BrowseTo(self): text = self.addressbar.text() i = self.tabbar.currentIndex() tab = self.tabbar.tabData(i) wv = self.findChild(QWidget, tab).content if "http" not in text: if "." not in text: url = "https://google.com/?q=" + text else: url = "https://" + text else: url = text wv.load(QUrl.fromUserInput(url)) def SetTabContent(self, i, type): tab_Name = self.tabs[i].objectName() count = 0 running = True while running: tab_data_name = self.tabbar.tabData(count) if count >= 99: running = False if tab_Name == tab_data_name["object"]: if type == "title": newTitle = self.findChild(QWidget, tab_Name).content.title() self.tabbar.setTabText(count, newTitle) elif type == "icon": newIcon = self.findChild(QWidget, tab_Name).content.icon() self.tabbar.setTabIcon(count, newIcon) running = False else: count += 1
class XTabWidget(QFrame): addClicked = pyqtSignal() currentChanged = pyqtSignal(int) tabCloseRequested = pyqtSignal(int) def __init__(self, QWidget_parent=None): super(XTabWidget, self).__init__(QWidget_parent) # setup self frame self.setFrameShadow(QFrame.Raised) # self.setFrameShape(QFrame.StyledPanel) self.setFrameShape(QFrame.NoFrame) # layouts self._layout = QVBoxLayout() self._layout.setContentsMargins(0, 0, 0, 0) self._layout.setSpacing(2) self._layout_top = QHBoxLayout() self._layout_top.setContentsMargins(0, 0, 0, 0) # stacked widget self._stack = QStackedWidget(self) # tab bar self._tabbar = QTabBar(self) self._tabbar.setTabsClosable(True) self._tabbar.setMovable(False) self._tabbar.setExpanding(False) self._tabbar.setShape(QTabBar.RoundedNorth) self._tabbar.currentChanged.connect(self.on_tab_current_changed) self._tabbar.tabCloseRequested.connect(self.on_tab_close_requested) # button "add" self._btn_add = QPushButton('+', self) self._btn_add.setMaximumSize(QSize(22, 22)) self._btn_add.clicked.connect(self.on_btn_add_clicked) # complete layout self._layout_top.addWidget(self._btn_add, 0, Qt.AlignVCenter) self._layout_top.addWidget(self._tabbar, 1, Qt.AlignVCenter) self._layout.addLayout(self._layout_top) self._layout.addWidget(self._stack) self.setLayout(self._layout) def addTab(self, widget: QWidget, title: str, closeable: bool = True) -> int: # add tab to tabbar tab_index = self._tabbar.addTab(title) if not closeable: self._tabbar.setTabButton(tab_index, QTabBar.RightSide, None) self._tabbar.setTabButton(tab_index, QTabBar.LeftSide, None) # it MAY be on the left too!! # add widget into stackedwidget self._stack.addWidget(widget) return tab_index def removeTab(self, index: int): # remove from tab bar self._tabbar.removeTab(index) # remove from stacked widget widget = self._stack.widget(index) if widget is not None: # Removes widget from the QStackedWidget. i.e., widget # is not deleted but simply removed from the stacked layout, # causing it to be hidden. self._stack.removeWidget(widget) # and now we probably want to delete it to avoid memory leak widget.close() widget.deleteLater() def tabBar(self) -> QTabBar: return self._tabbar def enableButtonAdd(self, enableState: bool = True): self._btn_add.setEnabled(enableState) def setCurrentIndex(self, index: int): self._stack.setCurrentIndex(index) self._tabbar.setCurrentIndex(index) def count(self) -> int: return self._tabbar.count() def tabWidget(self, index: int): """ Return page widget, inserted at index index :param index: :return: QWidget inserted at specified index, or None """ widget = self._stack.widget(index) return widget @pyqtSlot() def on_btn_add_clicked(self): self.addClicked.emit() @pyqtSlot(int) def on_tab_current_changed(self, idx: int): self._stack.setCurrentIndex(idx) self.currentChanged.emit(idx) @pyqtSlot(int) def on_tab_close_requested(self, idx: int): self.tabCloseRequested.emit(idx)
class App(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Web browser") self.setBaseSize(1366,768) self.create_app() def create_app(self): #main layout self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0,0,0,0) #tag self.qtbar = QTabBar(movable=True,tabsClosable=True) self.qtbar.tabCloseRequested.connect(self.closeTab) #tag plus self.addButton = QPushButton("+") self.addButton.clicked.connect(self.addtag) #addressbar -> search bar self.addressbar = addressBar() self.toolbar = QWidget() self.toolbarLayout = QHBoxLayout() self.toolbar.setLayout(self.toolbarLayout) self.toolbarLayout.addWidget(self.addressbar) self.toolbarLayout.addWidget(self.addButton) #To store tab and its content self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) #show the main app's image self.layout.addWidget(self.qtbar) self.layout.addWidget(self.toolbar) self.layout.addWidget(self.container) #record the tag self.tagcount = 0 self.tagObject = [] #initialize first tag self.addtag() self.setLayout(self.layout) self.show() def closeTab(self,i): self.qtbar.removeTab(i) def addtag(self): i = self.tagcount #one tab, one content -> a layout self.tagObject.append(QWidget()) self.tagObject[i].layout = QVBoxLayout() self.tagObject[i].setObjectName("tabs"+str(i)) #get content from website that you want to browse self.tagObject[i].content = QWebEngineView() self.tagObject[i].content.load(QUrl.fromUserInput("https://www.google.com")) self.tagObject[i].layout.addWidget(self.tagObject[i].content) self.tagObject[i].setLayout(self.tagObject[i].layout) #store this tag to container, that will help to keep content and avoid to be lost self.container.layout.addWidget(self.tagObject[i]) self.container.layout.setCurrentWidget(self.tagObject[i]) self.qtbar.addTab("New tab") self.tagcount+=1
class App(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Web Browser") # to open at a specific size self.setBaseSize(1366, 768) self.setMinimumSize(1366, 768) self.CreateApp() self.setWindowIcon(QIcon("logo.png")) def CreateApp(self): self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) # Create Tabs self.tabbar = QTabBar(movable=True, tabsClosable=True) self.tabbar.tabCloseRequested.connect(self.CloseTab) self.tabbar.tabBarClicked.connect(self.SwitchTab) self.tabbar.setCurrentIndex(0) self.tabbar.setDrawBase(False) self.tabbar.setLayoutDirection(Qt.LeftToRight) self.tabbar.setElideMode(Qt.ElideLeft) self.shortcutNewTab = QShortcut(QKeySequence("Ctrl+T"), self) self.shortcutNewTab.activated.connect(self.AddTab) self.shortcutReload = QShortcut(QKeySequence("Ctrl+R"), self) self.shortcutReload.activated.connect(self.ReloadPage) # Keep track of tabs self.tabCount = 0 # contains every widget in the tab self.tabs = [] # Set up all Buttons with their methods self.Toolbar = QWidget() self.Toolbar.setObjectName("Toolbar") self.ToolbarLayout = QHBoxLayout() self.addressbar = AddressBar() self.AddTabButton = QPushButton("+") self.BackButton = QPushButton("<") self.BackButton.clicked.connect(self.GoBack) self.ForwardButton = QPushButton(">") self.ReloadButton = QPushButton("R") self.ReloadButton.clicked.connect(self.ReloadPage) self.ForwardButton.clicked.connect(self.GoForward) self.addressbar.returnPressed.connect(self.BrowseTo) self.AddTabButton.clicked.connect(self.AddTab) # Build Toolbars self.Toolbar.setLayout(self.ToolbarLayout) self.ToolbarLayout.addWidget(self.BackButton) self.ToolbarLayout.addWidget(self.ForwardButton) self.ToolbarLayout.addWidget(self.ReloadButton) self.ToolbarLayout.addWidget(self.addressbar) self.ToolbarLayout.addWidget(self.AddTabButton) # Set main view self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) self.layout.addWidget(self.tabbar) self.layout.addWidget(self.Toolbar) self.layout.addWidget(self.container) self.setLayout(self.layout) self.AddTab() self.show() def CloseTab(self, i): self.tabbar.removeTab(i) def AddTab(self): i = self.tabCount self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].layout.setContentsMargins(0, 0, 0, 0) self.tabs[i].setObjectName("tab " + str(i)) # Open webview self.tabs[i].content = QWebEngineView() self.tabs[i].content.load(QUrl.fromUserInput("http://google.com")) self.tabs[i].content1 = QWebEngineView() self.tabs[i].content1.load(QUrl.fromUserInput("http://google.com")) self.tabs[i].content.titleChanged.connect( lambda: self.SetTabContent(i, "title")) self.tabs[i].content.iconChanged.connect( lambda: self.SetTabContent(i, "icon")) self.tabs[i].content.urlChanged.connect( lambda: self.SetTabContent(i, "url")) # Add webview to tabs layout self.tabs[i].splitview = QSplitter() self.tabs[i].layout.addWidget(self.tabs[i].splitview) self.tabs[i].splitview.addWidget(self.tabs[i].content) self.tabs[i].splitview.addWidget(self.tabs[i].content1) # set top level tab from [] to layout self.tabs[i].setLayout(self.tabs[i].layout) # add tab to top level stackedwidget self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) # Set the tab at top of screen # Set tabData to tab<#> So it knows what self.tabs(#) it needs to control self.tabbar.addTab("New Tab") self.tabbar.setTabData(i, {"object": "tab " + str(i), "initial": i}) ''' self.tabs[i].objectName = tab1 self.tabbar.tabData(i)["object"] = tab1 ''' self.tabbar.setCurrentIndex(i) self.tabCount += 1 def SwitchTab(self, i): if self.tabbar.tabData(i): tab_data = self.tabbar.tabData(i) print(tab_data) tab_content = self.tabs[i] print(tab_content) self.container.layout.setCurrentWidget(tab_content) new_url = tab_content.content.url().toString() self.addressbar.setText(new_url) def BrowseTo(self): text = self.addressbar.text() print(text) i = self.tabbar.currentIndex() print(i) tab = self.tabbar.tabData(i) print(tab) # wv = self.findChild(QWidget, tab).content if "http" not in text: if "." not in text: url = "https://google.com/#q=" + text else: url = "http://" + text else: url = text self.tabs[i].content.load(QUrl.fromUserInput(url)) def SetTabContent(self, i, type): print("im here") tab_name = self.tabs[i].objectName() print(tab_name) count = 0 running = True current_tab = self.tabbar.tabData(self.tabbar.currentIndex())["object"] if current_tab == tab_name and type == "url": new_url = self.tabs[i].content.url().toString() self.addressbar.setText(new_url) return False while running: tab_data_name = self.tabbar.tabData(count) print(tab_data_name) if count >= 99: running = False if tab_name == tab_data_name["object"]: if type == "title": print("im in here") newTitle = self.tabs[i].content.title() self.tabbar.setTabText(count, newTitle) running = False elif type == "icon": newIcon = self.tabs[i].content.icon() self.tabbar.setTabIcon(count, newIcon) running = False else: count += 1 def GoBack(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.tabs[activeIndex].content tab_content.back() pass def GoForward(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.tabs[activeIndex].content tab_content.forward() pass def ReloadPage(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.tabs[activeIndex].content tab_content.reload()
class ImportWindow(QWidget): def __init__(self, mainwindow): QWidget.__init__(self, mainwindow, Qt.Window) self._setupUi() self.doc = mainwindow.doc self.model = mainwindow.model.import_window self.swapOptionsComboBox = ComboboxModel(model=self.model.swap_type_list, view=self.swapOptionsComboBoxView) self.table = ImportTable(model=self.model.import_table, view=self.tableView) self.model.view = self self._setupColumns() # Can only be done after the model has been connected self.tabView.tabCloseRequested.connect(self.tabCloseRequested) self.tabView.currentChanged.connect(self.currentTabChanged) self.targetAccountComboBox.currentIndexChanged.connect(self.targetAccountChanged) self.importButton.clicked.connect(self.importClicked) self.swapButton.clicked.connect(self.swapClicked) def _setupUi(self): self.setWindowTitle(tr("Import")) self.resize(557, 407) self.verticalLayout = QVBoxLayout(self) self.tabView = QTabBar(self) self.tabView.setMinimumSize(QtCore.QSize(0, 20)) self.verticalLayout.addWidget(self.tabView) self.targetAccountLayout = QHBoxLayout() self.targetAccountLabel = QLabel(tr("Target Account:")) self.targetAccountLayout.addWidget(self.targetAccountLabel) self.targetAccountComboBox = QComboBox(self) self.targetAccountComboBox.setMinimumSize(QtCore.QSize(150, 0)) self.targetAccountLayout.addWidget(self.targetAccountComboBox) spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.targetAccountLayout.addItem(spacerItem) self.groupBox = QGroupBox(tr("Are some fields wrong? Fix them!")) self.gridLayout = QGridLayout(self.groupBox) self.swapOptionsComboBoxView = QComboBox(self.groupBox) self.gridLayout.addWidget(self.swapOptionsComboBoxView, 0, 0, 1, 2) self.applyToAllCheckBox = QCheckBox(tr("Apply to all accounts")) self.gridLayout.addWidget(self.applyToAllCheckBox, 1, 0, 1, 1) self.swapButton = QPushButton(tr("Fix")) self.gridLayout.addWidget(self.swapButton, 1, 1, 1, 1) self.targetAccountLayout.addWidget(self.groupBox) self.verticalLayout.addLayout(self.targetAccountLayout) self.tableView = TableView(self) self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tableView.setDragEnabled(True) self.tableView.setDragDropMode(QAbstractItemView.InternalMove) self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.horizontalHeader().setHighlightSections(False) self.tableView.horizontalHeader().setMinimumSectionSize(18) self.tableView.verticalHeader().setVisible(False) self.tableView.verticalHeader().setDefaultSectionSize(18) self.verticalLayout.addWidget(self.tableView) self.horizontalLayout = QHBoxLayout() spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem1) self.importButton = QPushButton(tr("Import")) self.horizontalLayout.addWidget(self.importButton) self.verticalLayout.addLayout(self.horizontalLayout) self.tabView.setTabsClosable(True) self.tabView.setDrawBase(False) self.tabView.setDocumentMode(True) self.tabView.setUsesScrollButtons(True) def _setupColumns(self): # Can't set widget alignment in a layout in the Designer l = self.targetAccountLayout l.setAlignment(self.targetAccountLabel, Qt.AlignTop) l.setAlignment(self.targetAccountComboBox, Qt.AlignTop) # --- Event Handlers def currentTabChanged(self, index): self.model.selected_pane_index = index def importClicked(self): self.model.import_selected_pane() def swapClicked(self): applyToAll = self.applyToAllCheckBox.isChecked() apply = ActionSelectionOptions.ApplyToAll if applyToAll else ActionSelectionOptions.ApplyToPane self.model.perform_swap(apply=apply) def tabCloseRequested(self, index): self.model.close_pane(index) self.tabView.removeTab(index) def targetAccountChanged(self, index): self.model.selected_target_account_index = index self.table.updateColumnsVisibility() # --- model --> view def close(self): self.hide() def close_selected_tab(self): self.tabView.removeTab(self.tabView.currentIndex()) def refresh_target_accounts(self): # We disconnect the combobox because we don't want the clear() call to set the selected # target index in the model. self.targetAccountComboBox.currentIndexChanged.disconnect(self.targetAccountChanged) self.targetAccountComboBox.clear() self.targetAccountComboBox.addItems(self.model.target_account_names) self.targetAccountComboBox.currentIndexChanged.connect(self.targetAccountChanged) def refresh_tabs(self): while self.tabView.count(): self.tabView.removeTab(0) for pane in self.model.panes: self.tabView.addTab(pane.name) def set_swap_button_enabled(self, enabled): self.swapButton.setEnabled(enabled) def show(self): # For non-modal dialogs, show() is not enough to bring the window at the forefront, we have # to call raise() as well QWidget.showNormal(self) QWidget.raise_(self) QWidget.activateWindow(self) def update_selected_pane(self): index = self.model.selected_pane_index if index != self.tabView.currentIndex(): # this prevents infinite loops self.tabView.setCurrentIndex(index) self.targetAccountComboBox.setCurrentIndex(self.model.selected_target_account_index) self.table.updateColumnsVisibility()
class DocStringsGUI(QWidget): def __init__(self): super().__init__() self.mod_dict_setup() # Make a list for new windows created and a var to keep track of how many there are self.pop_list = [] self.pop_amount = 0 # Setup child widgets self.child_setup() # Make connections self.mod_name_listbox.itemSelectionChanged.connect(self.doc_str_change) self.mod_name_listbox.itemSelectionChanged.connect( self.attr_list_change) self.attr_name_listbox.itemSelectionChanged.connect( self.doc_str_change_attr) self.exitButton.clicked.connect(self.exit) self.editButton.clicked.connect(self.save_changes) self.popButton.clicked.connect(self.window_pop) self.favButton.clicked.connect(self.fav) self.search_line.textChanged[str].connect(self.search) self.tabs.tabBarClicked.connect(self.get_tabs) # Size, place, and show the Window self.mod_name_listbox.setVerticalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff) self.resize(1300, 300) self.show() def mod_dict_setup(self): # modDocList contains a dictionary of mod names, with their classes and functions and doc strings. self.mod_doc_dict = check_file() # A shallow copy so the user can make changes without muking it up. self.user_dict = copy.copy(self.mod_doc_dict) try: with open('usrdict.json', 'r') as f: f.close() except: with open('usrdict.json', 'w') as f: json.dump(self.user_dict, f) f.close() def get_tabs(self): self.mod_name_listbox.clear() if self.tabs.currentIndex() == 0: for key in self.mod_doc_dict.keys(): if '*' in key: self.mod_name_listbox.addItem(key) else: for key in self.mod_doc_dict.keys(): self.mod_name_listbox.addItem(key) self.mod_name_listbox.sortItems() def search(self): self.mod_name_listbox.clear() # Search for all tab. if self.tabs.currentIndex() == 0: if self.search_line.text() == '': for key in self.mod_doc_dict.keys(): self.mod_name_listbox.addItem(key) else: if self.doc_checkbox.isChecked(): for key in self.mod_doc_dict.keys(): if self.search_line.text( ) in self.mod_doc_dict[key][0]: self.mod_name_listbox.addItem(key) for key in self.mod_doc_dict.keys(): if self.search_line.text() in key: self.mod_name_listbox.addItem(key) # Search for Favorites tab. else: for key in self.mod_doc_dict.keys(): if '*' in key and self.search_line.text() in key: self.mod_name_listbox.addItem(key) self.mod_name_listbox.sortItems() def fav(self): if not self.mod_name_listbox.currentItem().text().startswith('*'): self.user_dict[str('*' + self.mod_name_listbox.currentItem().text() )] = self.user_dict.pop( self.mod_name_listbox.currentItem().text()) self.mod_doc_dict[str('*' + self.mod_name_listbox.currentItem( ).text())] = self.mod_doc_dict.pop( self.mod_name_listbox.currentItem().text()) self.mod_name_listbox.currentItem().setText( '*' + self.mod_name_listbox.currentItem().text()) else: self.user_dict[self.mod_name_listbox.currentItem().text().replace( '*', '')] = self.user_dict.pop( self.mod_name_listbox.currentItem().text()) self.mod_doc_dict[ self.mod_name_listbox.currentItem().text().replace( '*', '')] = self.mod_doc_dict.pop( str(self.mod_name_listbox.currentItem().text())) self.mod_name_listbox.currentItem().setText( str(self.mod_name_listbox.currentItem().text()).replace( '*', '')) with open('usrdict.json', 'w') as f: json.dump(self.user_dict, f) f.close() def window_pop(self): try: self.pop_list.append( PopWindow(self.doc_str_textbox.toPlainText(), self.pop_window_title).exec_()) except: self.doc_str_textbox.setText( 'Please select a module, class, or function before trying to pop the window!' ) def save_changes(self): # Delete usrdict.json to reset changes try: if self.mod_doc_dict[self.mod_name_listbox.currentItem( ).text()][1][self.attr_name_listbox.currentItem().text().split( ' ', 2)[1]][1] is not None: modname = self.attr_name_listbox.currentItem().text().split( ' ', 2)[1] self.user_dict[self.mod_name_listbox.currentItem().text( )][1][modname][1] = self.doc_str_textbox.toPlainText() except AttributeError: try: self.user_dict[self.mod_name_listbox.currentItem().text( )][0] = self.doc_str_textbox.toPlainText() except AttributeError: pass with open('usrdict.json', 'w') as f: json.dump(self.user_dict, f) f.close() def doc_str_change(self): # change the docStr text to match the selected mod self.doc_str_textbox.setText( self.mod_doc_dict[self.mod_name_listbox.currentItem().text()][0]) self.pop_window_title = self.mod_name_listbox.currentItem().text() def doc_str_change_attr(self): # change the doc_str text to match the selected attr mod = self.mod_name_listbox.currentItem().text() attr = self.attr_name_listbox.currentItem().text().split(' ', 2)[1] self.pop_window_title = mod + ': ' + self.attr_name_listbox.currentItem( ).text() try: doc_str = self.mod_doc_dict[mod][1][attr][1] except KeyError: doc_str = 'None' self.doc_str_textbox.setText(doc_str) def attr_list_change(self): # If the attr listbox isn't empty, empty it then fill it self.attr_name_listbox.clear() # Make a list of attributes for the selected module from self.mod_doc_dict attr_name_list = self.mod_doc_dict[ self.mod_name_listbox.currentItem().text()][1] for i in attr_name_list.keys(): self.attr_name_listbox.addItem(str(attr_name_list[i][0]) + str(i)) self.attr_name_listbox.sortItems() def child_setup(self): # Set window title and make the labels and doc_str_textbox self.setWindowTitle('DocStrings GUI!') self.modNamelbl = QLabel('Module Names') self.attrlbl = QLabel('Attributes') self.docStrlbl = QLabel('Doc Strings') self.doc_str_textbox = QTextEdit(self) # Make the list boxes self.mod_name_listbox = QListWidget(self) self.attr_name_listbox = QListWidget(self) self.populate_childs() def populate_childs(self): # Add items, then sort them for mod in self.mod_doc_dict.keys(): self.mod_name_listbox.addItem(mod) self.mod_name_listbox.sortItems() # Set the size of the list boxes self.mod_name_listbox.setFixedSize(350, 500) self.attr_name_listbox.setFixedSize(350, 500) self.doc_str_textbox.setFixedSize(500, 500) # Create buttons self.favButton = QPushButton('Favorite') self.popButton = QPushButton('POP!') self.editButton = QPushButton('Save Edit') self.exitButton = QPushButton('Exit') # Create Search Bar self.search_line = QLineEdit('Search') self.tabs = QTabBar() self.tabs.addTab('All') self.tabs.addTab('Favorites') self.doc_checkbox = QCheckBox('Include Doc Strings in search') def exit(self): if mainWindow.pop_amount is not 0: mainWindow.setHidden(True) else: QCoreApplication.instance().exit() def menu_setup(self): self.menubar = MenuBar() def grid_setup(self): # ---TitleBar--------------------------------| # modNamelbl-------attNameListbox---docStrlbl|0 # modNamelistbox---attNameListbox--docStrText|1 # modNamelistbox---attNameListbox--docStrText|2 # modNamelistbox---attNameListbox--docStrText|3 # modNamelistbox---attNameListbox--docStrText|4 # modNamelistbox---attNameListbox--docStrText|5 # -------------------------------------------|6 # ----favbtn---popbtn----addbtn---exitbtn----|7 # ________________StatusBar__________________|8 # 0 1 2 3 4 5 6 7 8 # Make the grid and set spacing then place widgets in it self.grid = QGridLayout() self.grid.setSpacing(1) label = QLabel() self.grid.addWidget(label) self.grid.addWidget(self.menubar, 0, 1, 1, 40) self.grid.addWidget(self.doc_checkbox, 7, 6) self.grid.addWidget(self.tabs, 1, 3) self.grid.addWidget(self.modNamelbl, 1, 1) self.grid.addWidget(self.attrlbl, 1, 4) self.grid.addWidget(self.docStrlbl, 1, 7) self.grid.addWidget(self.mod_name_listbox, 2, 1, 5, 3) self.grid.addWidget(self.attr_name_listbox, 2, 4, 5, 3) self.grid.addWidget(self.doc_str_textbox, 2, 7, 5, 3) self.grid.addWidget(self.favButton, 7, 2) self.grid.addWidget(self.popButton, 7, 7) self.grid.addWidget(self.editButton, 7, 8) self.grid.addWidget(self.exitButton, 7, 9) self.grid.addWidget(self.search_line, 8, 6) # Change the layout to the grid self.setLayout(self.grid)
class App(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Web Browser") self.CreateApp() self.setBaseSize(1366, 786) def CreateApp(self): #Keep track of tabs self.tabCount = 0 self.tabs = [] self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) #Creating tabs self.tabbar = QTabBar(movable=True, tabsClosable=True) self.tabbar.tabCloseRequested.connect(self.CloseTab) self.tabbar.tabBarClicked.connect(self.SwitchTab) self.tabbar.setCurrentIndex(0) #create addressbar self.Toolbar = QWidget() self.ToolbarLayout = QHBoxLayout() self.addressbar = AddressBar() #new tab button self.AddTabButton = QPushButton("+") #connect address bar and button signals self.AddTabButton.clicked.connect(self.AddTab) self.addressbar.returnPressed.connect(self.BrowseTo) #set toolbar buttons self.BackButton = QPushButton("<") self.ForwardButton = QPushButton(">") self.RelaodButton = QPushButton("R") #connect toolbar buttons self.BackButton.clicked.connect(self.GoBack) self.ForwardButton.clicked.connect(self.GoForward) self.RelaodButton.clicked.connect(self.Reload) #build toolbar self.Toolbar.setLayout(self.ToolbarLayout) self.ToolbarLayout.addWidget(self.BackButton) self.ToolbarLayout.addWidget(self.ForwardButton) self.ToolbarLayout.addWidget(self.RelaodButton) self.ToolbarLayout.addWidget(self.addressbar) self.ToolbarLayout.addWidget(self.AddTabButton) #set main view self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) self.layout.addWidget(self.tabbar) self.layout.addWidget(self.Toolbar) self.layout.addWidget(self.container) self.setLayout(self.layout) self.AddTab() self.show() def CloseTab(self, i): self.tabbar.removeTab(i) def AddTab(self): i = self.tabCount self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() #giving id to tabs self.tabs[i].setObjectName("tab" + str(i)) #create and open web view self.tabs[i].content = QWebEngineView() self.tabs[i].content.load(QUrl.fromUserInput("http://google.com")) self.tabs[i].content.titleChanged.connect( lambda: self.SetTabContent(i, "title")) self.tabs[i].content.iconChanged.connect( lambda: self.SetTabContent(i, "icon")) self.tabs[i].content.urlChanged.connect( lambda: self.SetTabContent(i, "url")) #add web view to tabs layout self.tabs[i].layout.addWidget(self.tabs[i].content) #set top level tab from list to layout self.tabs[i].setLayout(self.tabs[i].layout) #add tab to top level stacked widget self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) #set tab at the top of the screen self.tabbar.addTab("New Tab") self.tabbar.setTabData(i, {"object": "tab{}".format(i), "initial": i}) self.tabbar.setCurrentIndex(i) self.tabCount += 1 def SwitchTab(self, i): if self.tabbar.tabData(i): td = self.tabbar.tabData(i)['object'] tabContent = self.findChild(QWidget, td) self.container.layout.setCurrentWidget(tabContent) new_url = tabContent.url().toString() self.addressbar.setText(new_url) def BrowseTo(self): text = self.addressbar.text() i = self.tabbar.currentIndex() td = self.tabbar.tabData(i)['object'] wv = self.findChild(QWidget, td).content if 'http' not in text: if "." not in text: url = "https://www.google.ca/#q={}".format(text) else: url = "http://{}".format(text) else: url = text wv.load(QUrl.fromUserInput(url)) def SetTabContent(self, i, type): tab_name = self.tabs[i].objectName() count = 0 running = True curr_tab = self.tabbar.tabData(self.tabbar.currentIndex())['object'] if curr_tab == tab_name and type == 'url': new_url = self.findChild(QWidget, tab_name).content.url().toString() self.addressbar.setText(new_url) return False while running: tab_data_name = self.tabbar.tabData(count) if count >= 99: running = False if tab_name == tab_data_name['object']: if type == 'title': newTitle = self.findChild(QWidget, tab_name).content.title() self.tabbar.setTabText(count, newTitle) elif type == 'icon': newIcon = self.findChild(QWidget, tab_name).content.icon() self.tabbar.setTabIcon(count, newIcon) running = False else: count += 1 def GoForward(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)['object'] tab_content = self.findChild(QWidget, tab_name).content tab_content.forward() def GoBack(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)['object'] tab_content = self.findChild(QWidget, tab_name).content tab_content.back() def Reload(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)['object'] tab_content = self.findChild(QWidget, tab_name).content tab_content.reload()
class App(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Web Browser") self.setMinimumSize(1366, 768) self.CreateApp() def CreateApp(self): #Create the Main Layout and Spacing self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) #Create the Tab Bar self.tabbar = QTabBar(movable=True, tabsClosable=True) self.tabbar.tabCloseRequested.connect(self.CloseTab) self.tabbar.tabBarClicked.connect(self.SwitchTab) self.tabbar.setCurrentIndex(0) self.tabbar.setDrawBase(False) self.tabbar.setLayoutDirection(Qt.LeftToRight) self.tabbar.setElideMode(Qt.ElideLeft) # Keyboard shortcuts self.shortcutNewTab = QShortcut(QKeySequence("Ctrl+T"), self) self.shortcutNewTab.activated.connect(self.AddTab) self.shortcutReload = QShortcut(QKeySequence("Ctrl+R"), self) self.shortcutReload.activated.connect(self.ReloadPage) #Keep track of tabs self.tabCount = 0 self.tabs = [] #Creating the Address Bar for the Browswer self.Toolbar = QWidget() self.Toolbar.setObjectName("Toolbar") self.ToolbarLayout = QHBoxLayout() self.addressbar = AddressBar() self.AddTabButton = QPushButton("+") #Connect AddressBar with Button Signals self.addressbar.returnPressed.connect(self.BrowseTo) self.AddTabButton.clicked.connect(self.AddTab) #Set Toolbar Buttons self.BackButton = QPushButton("<") self.BackButton.clicked.connect(self.GoBack) self.ForwardButton = QPushButton(">") self.ForwardButton.clicked.connect(self.GoForward) self.ReloadButton = QPushButton("⟲") self.ReloadButton.clicked.connect(self.ReloadPage) #Build the TOolbar self.Toolbar.setLayout(self.ToolbarLayout) self.ToolbarLayout.addWidget(self.BackButton) self.ToolbarLayout.addWidget(self.ForwardButton) self.ToolbarLayout.addWidget(self.ReloadButton) self.ToolbarLayout.addWidget(self.addressbar) self.ToolbarLayout.addWidget(self.AddTabButton) #Set Main View self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) #Add Widgets to the Layout self.layout.addWidget(self.tabbar) self.layout.addWidget(self.Toolbar) self.layout.addWidget(self.container) self.setLayout(self.layout) self.AddTab() self.show() def CloseTab(self, i): self.tabbar.removeTab(i) def AddTab(self): i = self.tabCount # Set self.tabs = QWidget self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].layout.setContentsMargins(0, 0, 0, 0) # For Tab Switching self.tabs[i].setObjectName("tab" + str(i)) # Open Webview self.tabs[i].content = QWebEngineView() self.tabs[i].content.load(QUrl.fromUserInput("http://www.google.com")) self.tabs[i].content.titleChanged.connect(lambda: self.SetTabContent(i, "title")) self.tabs[i].content.iconChanged.connect(lambda: self.SetTabContent(i, "icon")) self.tabs[i].content.urlChanged.connect(lambda: self.SetTabContent(i, "url")) # Add Widget to Tabs Layout self.tabs[i].layout.addWidget(self.tabs[i].content) #Set Top Level Tab from [] to Layout self.tabs[i].setLayout(self.tabs[i].layout) #Add tab to Top Level Stack Widgets self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) #Set the Tab at the Top of the Screen self.tabbar.addTab("New Tab") self.tabbar.setTabData(i, {"object": "tab" + str(i), "initial": i}) self.tabbar.setCurrentIndex(i) #Increase the Tab Count self.tabCount += 1 def SwitchTab(self, i): if self.tabbar.tabData(i): tab_data = self.tabbar.tabData(i)["object"] tab_content = self.findChild(QWidget, tab_data) self.container.layout.setCurrentWidget(tab_content) new_url = tab_content.content.url().toString() self.addressbar.setText(new_url) def BrowseTo(self): text = self.addressbar.text() i = self.tabbar.currentIndex() tab = self.tabbar.tabData(i)["object"] webview = self.findChild(QWidget, tab).content if "http" not in text: if "." not in text: url = "https://www.google.com/search?q=" + text else: url = "http://" + text else: url = text webview.load(QUrl.fromUserInput(url)) def SetTabContent(self, i, type): tab_name = self.tabs[i].objectName() count = 0 running = True current_tab = self.tabbar.tabData(self.tabbar.currentIndex())["object"] if current_tab == tab_name and type == "url": new_url = self.findChild(QWidget, tab_name).content.url().toString() self.addressbar.setText(new_url) return False while running: tab_data_name = self.tabbar.tabData(count) if count >= 99: running = False if tab_name == tab_data_name["object"]: if type == "title": newTitle = self.findChild(QWidget, tab_name).content.title() self.tabbar.setTabText(count, newTitle) elif type == "icon": newIcon = self.findChild(QWidget, tab_name).content.icon() self.tabbar.setTabIcon(count, newIcon) running = False else: count += 1 def GoBack(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.back() def GoForward(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.forward() def ReloadPage(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.reload()
class NCL_Editor(QWidget): def __init__(self): super().__init__() self.layout = QVBoxLayout() self.setLayout(self.layout) self.createEditor() def createEditor(self): self.tab_bar = QTabBar(movable=True, tabsClosable=True) self.tab_bar.tabCloseRequested.connect(self.CloseTab) self.tab_bar.tabBarClicked.connect(self.SwitchTab) self.tab_bar.setCurrentIndex(0) self.tab_bar.setLayoutDirection(Qt.LeftToRight) self.tab_bar.setElideMode(Qt.ElideLeft) self.tabCount = 0 self.activeTabs = 0 self.tabs = [] self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) self.AddNewTab() self.layout.addWidget(self.tab_bar) self.layout.addWidget(self.container) def CloseTab(self, i): self.tab_bar.removeTab(i) self.activeTabs -= 1 if self.activeTabs == 0: self.AddNewTab() self.activeTabs += 1 print(self.tabs) # self.tabCount -= 1 def SwitchTab(self, i): if self.tab_bar.tabData(i): tab_data = self.tab_bar.tabData(i)["object"] tab_widget = self.findChild(QWidget, tab_data) self.container.layout.setCurrentWidget(tab_widget) def AddNewTab(self): i = self.tabCount self.activeTabs += 1 self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].layout.setContentsMargins(0, 0, 0, 0) self.tabs[i].setObjectName("Tab" + str(i)) self.tabs[i].content = CodeEditor() self.tabs[i].layout.addWidget(self.tabs[i].content) self.tabs[i].setLayout(self.tabs[i].layout) self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) self.tab_bar.addTab("unnamed") self.tab_bar.setTabData(i, {"object": "unamed" + str(i)}) self.tab_bar.setCurrentIndex(i) self.tabCount += 1 def AddTab(self, file_string): i = self.tabCount self.activeTabs += 1 self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].layout.setContentsMargins(0, 0, 0, 0) self.tabs[i].setObjectName(file_string.rsplit('/', 1)[1]) self.tabs[i].content = CodeEditor() file = QFile(file_string) file.open(QFile.ReadOnly) self.tabs[i].content.setPlainText(QTextStream(file).readAll()) self.tabs[i].layout.addWidget(self.tabs[i].content) self.tabs[i].setLayout(self.tabs[i].layout) self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) self.tab_bar.addTab(file_string.rsplit('/', 1)[1]) self.tab_bar.setTabData(i, {"object": file_string.rsplit('/', 1)[1]}) self.tab_bar.setCurrentIndex(i) self.tabCount += 1
class WebBrowser(QFrame): def __init__(self): super().__init__() self.setWindowTitle('Web Browser') self.setBaseSize(1366, 768) self.setMinimumSize(1366, 768) self.createApp() self.setWindowIcon(QIcon('logo.png')) def createApp(self): self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) # TabBar self.tabBar = QTabBar(movable=True, tabsClosable=True) self.tabBar.tabCloseRequested.connect(self.closeTab) self.tabBar.tabBarClicked.connect(self.switchTab) # self.tabBar.addTab('Tab 1') # self.tabBar.addTab('Tab 2') # self.tabBar = QTabWidget() # self.tabBar.addTab(QPushButton('Tab 1'), 'First Tab') # self.tabBar.addTab(QPushButton('Tab 2'), 'Second Tab') self.tabBar.setCurrentIndex(0) # Which Tab in the row of tabs is active self.tabBar.setDrawBase(False) self.tabBar.setLayoutDirection(Qt.LeftToRight) self.tabBar.setElideMode(Qt.ElideLeft) # Create Key shortcuts self.shortcutNewTab = QShortcut(QKeySequence('Ctrl+T'), self) self.shortcutNewTab.activated.connect(self.addTab) self.shortcutReload = QShortcut(QKeySequence('Ctrl+R'), self) self.shortcutReload.activated.connect(self.reload) # Keep track of tabs self.tabCount = 0 self.tabs = [] # Create address bar self.toolBar = QWidget() self.toolBar.setObjectName('toolBar') self.toolBarLayout = QHBoxLayout() self.addressBar = AddressBar() self.addressBar.returnPressed.connect(self.browseToFromAddressBar) # New Tab Button self.addTabButton = QPushButton('+') self.addTabButton.clicked.connect(self.addTab) # Set Toolbar Buttons like Back button, Reload etc. self.bwdButton = QPushButton('<') self.bwdButton.clicked.connect(self.navigateBwd) self.fwdButton = QPushButton('>') self.fwdButton.clicked.connect(self.navigateFwd) self.rldButton = QPushButton('R') self.rldButton.clicked.connect(self.reload) # Build Toolbar self.toolBar.setLayout(self.toolBarLayout) self.toolBarLayout.addWidget(self.bwdButton) self.toolBarLayout.addWidget(self.fwdButton) self.toolBarLayout.addWidget(self.rldButton) self.toolBarLayout.addWidget(self.addressBar) self.toolBarLayout.addWidget(self.addTabButton) # Set Main View self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) self.layout.addWidget(self.tabBar) self.layout.addWidget(self.toolBar) self.layout.addWidget(self.container) self.setLayout(self.layout) self.show() def closeTab(self, i): self.tabBar.removeTab(i) def addTab(self): i = self.tabCount self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].layout.setContentMargins(0, 0, 0, 0) self.tabs[i].setObjectName('tab' + str(i)) self.tabs[i].content = QWebEngineView() self.tabs[i].content.load(QUrl.fromUserInput('http://google.com')) # Update the title of the Tab when the URL changes self.tabs[i].content.titleChanged.connect(lambda : self.setTabContent(i, 'Title')) self.tabs[i].content.iconChanged.connect(lambda : self.setTabContent(i, 'Icon')) self.tabs[i].content.urlChanged.connect(lambda: self.setTabContent(i, 'Url')) # Add webview to tabs layout self.tabs[i].splitview = QSplitter() self.tabs[i].splitview.setOrientation(Qt.Vertical) self.tabs[i].layout.addWidget(self.tabs[i].splitview) self.tabs[i].splitview.addWidget(self.tabs[i].content) # Set top level tab in list to Layout self.tabs.setLayout(self.tabs[i].layout) # Add tab to top level stacked widget self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) # Set the tab at the top of the screen self.tabBar.addTab('New Tab') self.tabBar.setTabData(i, {'object': 'tab' + str(i), 'initial': i}) self.tabBar.setCurrentIndex(i) self.tabCount += 1 def switchTab(self, i): if self.tabBar.tabData(i): tabData = self.tabBar.tabData(i) tab_widget = self.findChild(QWidget, tabData) self.container.layout.setCurrentWidget(tab_widget) new_url = tab_widget.url().toString() self.addressBar.setText(new_url) def browseToFromAddressBar(self): txtLine = self.addressBar.text() i = self.tabBar.currentIndex() tabData = self.tabBar.tabData(i) tab_content = self.findChild(QWidget, tabData).content if 'http' not in txtLine: if '.' not in txtLine: url = 'https://www.google.com/search?q=' + str(txtLine) else: url = 'http://' + str(txtLine) else: url = txtLine tab_content.load(QUrl.fromUserInput(url)) def setTabContent(self, i, type): tab_name = self.tabs[i].objectName() count = 0 running = True current_tab = self.tabBar.tabData(self.tabBar.currentIndex())['object'] if current_tab == tab_name and type == 'Url': new_url = self.findChild(QWidget, tab_name).content.url().toString() self.addressBar.setText(new_url) return False while running: tab_data_name = self.tabBar.tabData(count) if count > 99: running = False if tab_name == tab_data_name['object']: if type == 'Title': newTitle = self.findChild(QWidget, tab_name).content.title() self.tabBar.setTabText(count, newTitle) elif type == 'Icon': newIcon = self.findChild(QWidget, tab_name).content.icon() self.tabBar.setTabIcon(count, newIcon) running = False else: count += 1 def navigateBwd(self): activeIndex = self.tabBar.currentIndex() tab_name = self.tabBar.tabData(activeIndex)['object'] tab_content = self.findChild(QWidget, tab_name).content tab_content.back() def navigateFwd(self): activeIndex = self.tabBar.currentIndex() tab_name = self.tabBar.tabData(activeIndex)['object'] tab_content = self.findChild(QWidget, tab_name).content tab_content.forward() def reload(self): activeIndex = self.tabBar.currentIndex() tab_name = self.tabBar.tabData(activeIndex)['object'] tab_content = self.findChild(QWidget, tab_name).content tab_content.reload()
class CMWConfig(QWidget): """CMWConfig is a QWidget with tabs for configuration management""" def __init__(self, parent=None): QWidget.__init__(self, parent) #self.lab_title = QLabel ('Configuration settings') #self.lab_status = QLabel ('Status: ') self.but_close = QPushButton('&Close') self.but_save = QPushButton('&Save') self.but_show = QPushButton('Show &Image') self.hboxW = QHBoxLayout() self.hboxB = QHBoxLayout() #self.hboxB.addWidget(self.lab_status) self.hboxB.addStretch(1) self.hboxB.addWidget(self.but_close) self.hboxB.addWidget(self.but_save) self.hboxB.addWidget(self.but_show) self.tab_names = ['Parameters', 'Configuration File'] self.gui_win = None self.make_tab_bar() self.gui_selector(cp.current_config_tab.value()) self.vbox = QVBoxLayout() self.vbox.addWidget(self.tab_bar) self.vbox.addLayout(self.hboxW) self.vbox.addStretch(1) self.vbox.addLayout(self.hboxB) self.setLayout(self.vbox) self.but_close.clicked.connect(self.on_close) self.but_save.clicked.connect(self.on_save) self.but_show.clicked.connect(self.on_show) self.set_tool_tips() self.set_style() def set_tool_tips(self): #msg = 'Edit field' self.but_close.setToolTip('Close this window.') self.but_save.setToolTip('Save all current configuration parameters.') self.but_show.setToolTip('Show ...') def set_style(self): self.setStyleSheet(style.styleBkgd) self.but_close.setStyleSheet(style.styleButton) self.but_save.setStyleSheet(style.styleButton) self.but_show.setStyleSheet(style.styleButton) self.setMinimumSize(600, 360) is_visible = False #self.lab_status.setVisible(False) self.but_close.setVisible(is_visible) self.but_save.setVisible(is_visible) self.but_show.setVisible(is_visible) def make_tab_bar(self): self.tab_bar = QTabBar() #Uses self.tab_names self.ind_tab_0 = self.tab_bar.addTab(self.tab_names[0]) self.ind_tab_1 = self.tab_bar.addTab(self.tab_names[1]) self.tab_bar.setTabTextColor(self.ind_tab_0, QColor('magenta')) self.tab_bar.setTabTextColor(self.ind_tab_1, QColor('magenta')) self.tab_bar.setShape(QTabBar.RoundedNorth) #self.tab_bar.setTabsClosable(True) #self.tab_bar.setMovable(True) #self.tab_bar.setTabEnabled(1, False) #self.tab_bar.setTabEnabled(2, False) tab_index = self.tab_names.index(cp.current_config_tab.value()) #try : # tab_index = self.tab_names.index(cp.current_config_tab.value()) #except : # tab_index = 1 # cp.current_config_tab.setValue(self.tab_names[tab_index]) self.tab_bar.setCurrentIndex(tab_index) logger.debug(' make_tab_bar - set tab: ' + cp.current_config_tab.value()) #self.connect(self.tab_bar, QtCore.SIGNAL('currentChanged(int)'), self.on_tab_bar) self.tab_bar.currentChanged[int].connect(self.on_tab_bar) def gui_selector(self, tab_name): #try : self.gui_win.close() #except : pass #try : del self.gui_win #except : pass if self.gui_win is not None: self.gui_win.close() del self.gui_win w_height = 120 if tab_name == self.tab_names[0]: self.gui_win = CMWConfigPars(self) elif tab_name == self.tab_names[1]: self.gui_win = CMWConfigFile(self) w_height = 170 else: logger.warning('Unknown tab name "%s"' % tab_name) #self.set_status(0, 'Set configuration file') self.gui_win.setFixedHeight(w_height) self.hboxW.addWidget(self.gui_win) self.gui_win.setVisible(True) def current_tab_index_and_name(self): tab_ind = self.tab_bar.currentIndex() tab_name = str(self.tab_bar.tabText(tab_ind)) return tab_ind, tab_name def on_tab_bar(self): tab_ind, tab_name = self.current_tab_index_and_name() logger.info('Selected tab "%s"' % tab_name) cp.current_config_tab.setValue(tab_name) self.gui_selector(tab_name) def set_parent(self, parent): self.parent = parent #def resizeEvent(self, e): #logger.debug('resizeEvent') #print self._name + ' config: self.size():', self.size() #self.setMinimumSize( self.size().width(), self.size().height()-40 ) #pass #def moveEvent(self, e): #logger.debug('moveEvent') #self.position = self.mapToGlobal(self.pos()) #self.position = self.pos() #logger.debug('moveEvent: new pos:' + str(self.position)) #pass def closeEvent(self, e): logger.debug('closeEvent') self.tab_bar.close() if self.gui_win is not None: self.gui_win.close() QWidget.close(self) def on_close(self): logger.debug('on_close') self.close() def on_save(self): logger.debug('on_save') cp.saveParametersInFile(cp.fname_cp.value()) def on_show(self): logger.debug('on_show - is not implemented yet...')
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)
class App(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Web Browser") self.create_app() self.setMinimumSize(1366, 768) self.setBaseSize(1366, 786) self.setWindowIcon(QIcon("TA logo BLK.png")) def create_app(self): # Setting main window layout self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) # Create keyboard shortcut --> new tab, reload self.shortcut_newtab = QShortcut(QKeySequence("Ctrl+t"), self) self.shortcut_newtab.activated.connect(self.add_tab) self.shortcut_reload = QShortcut(QKeySequence("Ctrl+r"), self) self.shortcut_reload.activated.connect(self.reload_page) # Create tabs --> Set tab bar, add tabs, close tabs self.tabbar = QTabBar(movable=True, tabsClosable=True) self.tabbar.tabCloseRequested.connect(self.close_tab) # Switch tab bar when clicked self.tabbar.tabBarClicked.connect(self.switch_tab) # Set index, tell which tab active self.tabbar.setCurrentIndex(0) self.tabbar.setDrawBase(False) # Keep track of tabs and content self.tab_count = 0 self.tabs = [] # Create address bar self.toolbar = QWidget() self.toolbar.setObjectName("Toolbar") self.toolbar_layout = QHBoxLayout() self.addressbar = AddressBar() # Connect address bar, button signal --> new tab, back, forward self.addressbar.returnPressed.connect(self.browse_to) self.add_tab_button = QPushButton("+") self.add_tab_button.clicked.connect(self.add_tab) self.back_button = QPushButton("<-") self.back_button.clicked.connect(self.go_back) self.forward_button = QPushButton("->") self.forward_button.clicked.connect(self.go_forward) self.reload_button = QPushButton("R") self.reload_button.clicked.connect(self.reload_page) # Create toolbar widget, add item self.toolbar.setLayout(self.toolbar_layout) self.toolbar_layout.addWidget(self.back_button) self.toolbar_layout.addWidget(self.forward_button) self.toolbar_layout.addWidget(self.reload_button) self.toolbar_layout.addWidget(self.addressbar) self.toolbar_layout.addWidget(self.add_tab_button) # Set main view, stacked layout self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) # Put elements in widget, set layout to widget self.layout.addWidget(self.tabbar) self.layout.addWidget(self.toolbar) self.layout.addWidget(self.container) self.setLayout(self.layout) self.add_tab() self.show() # Close tab, pass index def close_tab(self, i): self.tabbar.removeTab(i) # Add tabs def add_tab(self): i = self.tab_count self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].layout.setContentsMargins(0, 0, 0, 0) # Set object name, for switching tabs self.tabs[i].setObjectName("tab" + str(i)) # Web engine view --> object page loads into self.tabs[i].content = QWebEngineView() self.tabs[i].content.load(QUrl.fromUserInput("http://wwww.bing.com")) """ # Add to code for second window of splitview self.tabs[i].content1 = QWebEngineView() self.tabs[i].content1.load(QUrl.fromUserInput("http://wwww.bing.com")) """ # Update title text, icon, address bar self.tabs[i].content.titleChanged.connect( lambda: self.set_tab_content(i, "title")) self.tabs[i].content.iconChanged.connect( lambda: self.set_tab_content(i, "icon")) self.tabs[i].content.urlChanged.connect( lambda: self.set_tab_content(i, "url")) # Add webview content to layout (good for developer tools) self.tabs[i].splitview = QSplitter() self.tabs[i].splitview.setOrientation(Qt.Vertical) self.tabs[i].layout.addWidget(self.tabs[i].splitview) """ # Add content to split view self.tabs[i].splitview.addWidget(self.tabs[i].content) self.tabs[i].splitview.addWidget(self.tabs[i].content1) """ # Set top level tab from list to layout self.tabs[i].setLayout(self.tabs[i].layout) # Add tab to top level stacked Widget self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) # Show tab at top of screen, set tab data to website of tab self.tabbar.addTab("New Tab") self.tabbar.setTabData(i, {"object": "tab" + str(i), "initial": i}) self.tabbar.setCurrentIndex(i) # Add to tab count self.tab_count += 1 def switch_tab(self, i): # Get tab data, return object name want to switch to tab_data = self.tabbar.tabData(i)["object"] # If tab data exists, can click on tabs if self.tabbar.tabData(i): # Make tab index static tab_widget = self.findChild(QWidget, tab_data) self.container.layout.setCurrentWidget(tab_widget) # Change url in address bar with tab change new_url = tab_widget.content.url().toString() self.addressbar.setText(new_url) def browse_to(self): # Get text in address bar text = self.addressbar.text() # Get index # of current tab, get tab name, get webview associate with name i = self.tabbar.currentIndex() tab = self.tabbar.tabData(i)["object"] web_view = self.findChild(QWidget, tab).content # Check if address or search term if "http" not in text: if "." not in text: url = "https://www.bing.com/search?q=" + text else: url = "http://" + text else: url = text web_view.load(QUrl.fromUserInput(url)) def set_tab_content(self, i, type): """ self.tabs[i].objectName = tab1 self.tabbar.tabData(i)["object"] = tab1 """ tab_name = self.tabs[i].objectName() count = 0 running = True current_tab = self.tabbar.tabData(self.tabbar.currentIndex())["object"] if current_tab == tab_name and type == "url": new_url = self.findChild(QWidget, tab_name).content.url().toString() self.addressbar.setText(new_url) return False while running: # Get tab data tab_data_name = self.tabbar.tabData(count) if count >= 99: running = False if tab_name == tab_data_name["object"]: if type == "title": new_title = self.findChild(QWidget, tab_name).content.title() self.tabbar.setTabText(count, new_title) elif type == "icon": new_icon = self.findChild(QWidget, tab_name).content.icon() self.tabbar.setTabIcon(count, new_icon) running = False else: count += 1 def go_back(self): active_index = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(active_index)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.back() def go_forward(self): active_index = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(active_index)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.forward() def reload_page(self): active_index = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(active_index)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.reload()
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)
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 CGWMainTabs(QWidget): """GUI for tabs and associated widgets """ tab_names = ['User', 'Expert'] tab_ind_user = 0 tab_ind_expert = 1 def __init__(self, **kwargs): self.kwargs = kwargs parent = kwargs.get('parent', None) QWidget.__init__(self, parent) self.box_layout = QHBoxLayout() self.gui_win = None self.make_tab_bar() self.gui_selector(self.tab_names[1]) self.box = QVBoxLayout(self) self.box.addWidget(self.tab_bar) self.box.addLayout(self.box_layout) #self.box.addStretch(1) self.setLayout(self.box) self.show_tool_tips() self.set_style() #-------------------------- def show_tool_tips(self): self.setToolTip('Main tab window') #------------------- def sizeHint(self): height = 400 if self.tab_bar.currentIndex( ) == self.tab_ind_expert else 50 return QSize(300, height) #------------------- def set_style(self): from psdaq.control_gui.Styles import style from psdaq.control_gui.QWIcons import icon icon.set_icons() self.setWindowIcon(icon.icon_monitor) self.setStyleSheet(style.styleBkgd) self.layout().setContentsMargins(0, 0, 0, 0) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred) #self.setMinimumSize(300,300) #self.palette = QPalette() #self.resetColorIsSet = False #self.butELog .setIcon(icon.icon_mail_forward) #self.butFile .setIcon(icon.icon_save) #self.butExit .setIcon(icon.icon_exit) #self.butLogger .setIcon(icon.icon_logger) #self.butFBrowser.setIcon(icon.icon_browser) #self.butSave .setIcon(icon.icon_save_cfg) #self.butStop .setIcon(icon.icon_stop) #self.setMinimumHeight(250) #self.setMinimumWidth(550) #self.adjustSize() #self. setStyleSheet(style.styleBkgd) #self.butSave.setStyleSheet(style.styleButton) #self.butFBrowser.setVisible(False) #self.butExit.setText('') #self.butExit.setFlat(True) #------------------- def make_tab_bar(self): self.tab_bar = QTabBar() #len(self.tab_names) for tab_name in self.tab_names: tab_ind = self.tab_bar.addTab(tab_name) self.tab_bar.setTabTextColor(tab_ind, QColor('blue')) #gray, red, grayblue #self.tab_bar.setTabsClosable(True) #self.tab_bar.setMovable(True) self.tab_bar.setShape(QTabBar.RoundedNorth) tab_index = self.tab_ind_expert # self.tab_names.index(self.tab_names[self.tab_ind_expert]) self.tab_bar.setCurrentIndex(tab_index) logger.debug('make_tab_bar - set tab index: %d' % tab_index) self.tab_bar.currentChanged['int'].connect(self.on_tab_bar) self.tab_bar.tabCloseRequested.connect(self.on_tab_close_request) self.tab_bar.tabMoved[int, int].connect(self.on_tab_moved) #-------------------------- def gui_selector(self, tab_name): if self.gui_win is not None: #self.box_layout.removeWidget(self.gui_win) #self.gui_win.setVisible(False) self.gui_win.close() del self.gui_win w_height = 100 if tab_name == self.tab_names[1]: self.gui_win = CGWMainTabExpert(**self.kwargs) self.setMinimumHeight(400) w_height = 350 elif tab_name == self.tab_names[0]: self.gui_win = CGWMainTabUser(**self.kwargs) #self.gui_win = QTextEdit(tab_name) self.setFixedHeight(110) #self.setMinimumHeight(100) #self.gui_win.setFixedHeight(100) w_height = 70 else: self.gui_win = QTextEdit('Default window for tab %s' % tab_name) #self.gui_win.setMaximumHeight(w_height) #self.gui_win.setMaximumWidth(500) #self.gui_win.setFixedHeight(w_height) self.gui_win.setMinimumHeight(w_height) self.gui_win.setVisible(True) self.box_layout.addWidget(self.gui_win) #self.setStatus(0, s_msg) #------------------- def current_tab_index_and_name(self): tab_ind = self.tab_bar.currentIndex() tab_name = str(self.tab_bar.tabText(tab_ind)) return tab_ind, tab_name #------------------- def on_tab_bar(self, ind): tab_ind, tab_name = self.current_tab_index_and_name() logger.info('Selected tab "%s"' % tab_name) #cp.main_tab_name.setValue(tab_name) self.gui_selector(tab_name) #------------------- def on_tab_close_request(self, ind): logger.debug('on_tab_close_request ind:%d' % ind) #self.tab_bar.removeTab(ind) #logger.debug('on_tab_close_request tab index:%d' % (itab)) #------------------- def on_tab_moved(self, inew, iold): logger.debug('on_tab_close_request tab index begin:%d -> end:%d' % (iold, inew)) #------------------- #def resizeEvent(self, e): #pass #self.frame.setGeometry(self.rect()) #logger.debug('resizeEvent') #logger.debug('CGWMainTabs resizeEvent: %s' % str(self.size())) #def moveEvent(self, e): #logger.debug('moveEvent') #self.position = self.mapToGlobal(self.pos()) #self.position = self.pos() #logger.debug('moveEvent - pos:' + str(self.position)) #pass def closeEvent(self, e): logger.debug('CGWMainTabs.closeEvent') #try : self.gui_win.close() #except : pass #try : del self.gui_win #except : pass self.tab_bar.close() if self.gui_win is not None: self.gui_win.close() QWidget.closeEvent(self, e) def onExit(self): logger.debug('onExit') self.close() def set_tabs_visible(self, is_visible): logger.debug('set_tabs_visible: is_visible %s' % is_visible) self.tab_bar.setVisible(is_visible) def tab_bar_is_visible(self): return self.tab_bar.isVisible() def view_hide_tabs(self): self.tab_bar.setVisible(not self.tab_bar.isVisible()) def key_usage(self): return 'Keys:'\ '\n V - view/hide tabs'\ '\n' if __name__ == "__main__": def keyPressEvent(self, e): #logger.debug('keyPressEvent, key=%s' % e.key()) if e.key() == Qt.Key_Escape: self.close() elif e.key() == Qt.Key_V: self.view_hide_tab() else: logger.debug(self.key_usage())
class App(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Web Browser") print("call init") self.create_app() self.setBaseSize(1366, 768) def create_app(self): print("create app") self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0,0,0,0) # Create Tabs self.tabbar = QTabBar(movable=True, tabsClosable=True) self.tabbar.tabCloseRequested.connect(self.close_tab) self.tabbar.tabBarClicked.connect(self.SwitchTab) self.tabbar.setCurrentIndex(0) # Keep track of tabs self.tabCount = 0 self.tabs =[] # Create AddressBar self.Toolbar = QWidget() self.ToolbarLayout = QHBoxLayout() self.addressbar = AddressBar() self.AddTabButton = QPushButton("+") self.addressbar.returnPressed.connect(self.BrowseTo) self.AddTabButton.clicked.connect(self.AddTab) self.Toolbar.setLayout(self.ToolbarLayout) self.ToolbarLayout.addWidget(self.addressbar) self.ToolbarLayout.addWidget(self.AddTabButton) # set main view self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) self.layout.addWidget(self.tabbar) self.layout.addWidget(self.Toolbar) self.layout.addWidget(self.container) self.setLayout(self.layout) print("run show") self.AddTab() self.show() def close_tab(self, i): self.tabbar.removeTab(i) def AddTab(self): i = self.tabCount self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].setObjectName("tab" + str(i)) # open webview self.tabs[i].content = QWebEngineView() self.tabs[i].content.load(QUrl.fromUserInput("http://google.com")) self.tabs[i].content.titleChanged.connect(lambda: self.SetTabText(i)) # Add webview to tabs layout self.tabs[i].layout.addWidget(self.tabs[i].content) # set top level tab from [] to layout self.tabs[i].setLayout(self.tabs[i].layout) # add tab to the top level stacked widget self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) # set the tab at top of screen self.tabbar.addTab("New Tab") self.tabbar.setTabData(i, {"object": 'tab' + str(i), "initial": i}) self.tabbar.setCurrentIndex(i) self.tabCount += 1 def SwitchTab(self, i): tab_data = self.tabbar.tabData(i) print("tab: ", tab_data) tab_content = self.findChild(QWidget, tab_data) self.container.layout.setCurrentWidget(tab_content) def BrowseTo(self): text = self.addressbar.text() print("text") i = self.tabbar.currentIndex() tab = self.tabbar.tabData(i)["object"] wv = self.findChild(QWidget, tab).content if "http" not in text: if "." not in text: url = "https://www.google.com/search?q=" + text else: url ="http://" + text else: url = text wv.load(QUrl.fromUserInput(url)) def SetTabText(self, i): ''' self.tabs[i].objectName = tab1 self.tabbar.tabData(i)["object"] = tab1 ''' tab_name = self.tabs[i].objectName() # tab1 count = 0 running = True while running: tab_data_name = self.tabbar.tabData(count) if count > 99: running = False if tab_name == tab_data_name["object"]: newTitle = self.findChild(QWidget, tab_name).content.title() self.tabbar.setTabText(count, newTitle) running = False else: count +=1
class CMWMainTabs(QWidget): """GUI for tabs and associated widgets """ tab_names = [ 'CDB', 'Image', 'Text', 'Calib', 'HDF5', 'XTC', 't-converter', 'Configuration', 'Mask' ] tool_tips = [\ 'Calibration Data Base\nviewer/manager',\ 'Image Viewer for ndarrays',\ 'Text Browser for text-like calibration constants',\ 'File Manager for easy access calibration constants\nunder experimental calib directory',\ 'HDF5 file browser',\ 'XTC data viewer',\ 'Time converter between Date&Time <-> POSIX <-> LCLS2',\ 'Configuration manager for this app',\ 'Mask Editor for images',\ ] def __init__(self, parent=None, app=None): QWidget.__init__(self, parent) cp.cmwmaintabs = self self.box_layout = QHBoxLayout() start_tab_name = cp.main_tab_name.value() self.gui_win = None self.make_tab_bar(start_tab_name) self.gui_selector(start_tab_name) self.box = QVBoxLayout(self) self.box.addWidget(self.tab_bar) self.box.addLayout(self.box_layout) self.setLayout(self.box) self.set_tool_tips() self.set_style() def set_tool_tips(self): for t, s in zip(self.tab_names, self.tool_tips): self.tab_bar.setTabToolTip(self.tab_names.index(t), s) def set_style(self): from psana.graphqt.Styles import style from psana.graphqt.QWIcons import icon icon.set_icons() self.setWindowIcon(icon.icon_monitor) self.setStyleSheet(style.styleBkgd) self.layout().setContentsMargins(0, 0, 0, 0) def make_tab_bar(self, start_tab_name): self.tab_bar = QTabBar() for tab_name in self.tab_names: tab_ind = self.tab_bar.addTab(tab_name) self.tab_bar.setTabTextColor(tab_ind, QColor('blue')) #gray, red, grayblue self.tab_bar.setShape(QTabBar.RoundedNorth) tab_index = self.tab_names.index(start_tab_name) self.tab_bar.setCurrentIndex(tab_index) logger.debug('make_tab_bar - set tab index: %d' % tab_index) self.tab_bar.currentChanged['int'].connect(self.on_tab_bar) self.tab_bar.tabCloseRequested.connect(self.on_tab_close_request) self.tab_bar.tabMoved[int, int].connect(self.on_tab_moved) def gui_selector(self, tab_name): if self.gui_win is not None: self.gui_win.close() del self.gui_win w_height = 200 if cp.cmwmain is not None: cp.cmwmain.wlog.setVisible(True) if tab_name == 'CDB': from psana.graphqt.CMWDBMain import CMWDBMain self.gui_win = CMWDBMain() w_height = 500 elif tab_name == 'Configuration': from psana.graphqt.CMWConfig import CMWConfig self.gui_win = CMWConfig() w_height = 500 elif tab_name == 't-converter': from psana.graphqt.QWDateTimeSec import QWDateTimeSec self.gui_win = QWDateTimeSec() self.gui_win.setMaximumWidth(400) w_height = 80 elif tab_name == 'HDF5': from psana.graphqt.H5VMain import H5VMain #if cp.cmwmain is not None: cp.cmwmain.wlog.setVisible(False) self.gui_win = H5VMain() elif tab_name == 'Calib': from psana.graphqt.FMW1Main import FMW1Main self.gui_win = FMW1Main() #from psana.graphqt.FMWTabs import FMWTabs #self.gui_win = FMWTabs() elif tab_name == 'Image': from psana.graphqt.IVMain import IVMain #if cp.cmwmain is not None: cp.cmwmain.wlog.setVisible(False) self.gui_win = IVMain() elif tab_name == 'Text': from psana.graphqt.QWTextBrowser import QWTextBrowser self.gui_win = QWTextBrowser() elif tab_name == 'XTC': from psana.graphqt.DMQWMain import DMQWMain self.gui_win = DMQWMain() elif tab_name == 'Mask': self.gui_win = QTextEdit('Selected tab "%s"' % tab_name) else: self.gui_win = QTextEdit('Selected tab "%s"' % tab_name) #self.gui_win.setMinimumHeight(w_height) self.gui_win.setVisible(True) self.box_layout.addWidget(self.gui_win) def current_tab_index_and_name(self): tab_ind = self.tab_bar.currentIndex() tab_name = str(self.tab_bar.tabText(tab_ind)) return tab_ind, tab_name def on_tab_bar(self, ind): tab_ind, tab_name = self.current_tab_index_and_name() logger.info('Selected tab "%s"' % tab_name) cp.main_tab_name.setValue(tab_name) self.gui_selector(tab_name) def on_tab_close_request(self, ind): logger.debug('on_tab_close_request ind:%d' % ind) #self.tab_bar.removeTab(ind) def on_tab_moved(self, inew, iold): logger.debug('on_tab_close_request tab index begin:%d -> end:%d' % (iold, inew)) def closeEvent(self, e): logger.debug('closeEvent') if self.gui_win is not None: self.gui_win.close() QWidget.closeEvent(self, e) cp.cmwmaintabs = None def onExit(self): logger.debug('onExit') self.close() def set_tabs_visible(self, is_visible): logger.debug('set_tabs_visible: is_visible %s' % is_visible) self.tab_bar.setVisible(is_visible) def tab_bar_is_visible(self): return self.tab_bar.isVisible() def view_hide_tabs(self): self.tab_bar.setVisible(not self.tab_bar.isVisible()) def view_data(self, data=None, fname=None): from psana.pyalgos.generic.NDArrUtils import info_ndarr, np cp.last_selected_data = data cp.last_selected_fname.setValue(fname) if data is None and fname is None: logger.debug('data and fname are None - do not switch to viewer') elif data is None: tabname = 'Text' if 'geometry' in fname or 'common_mode' in fname else 'Image' self.set_tab(tabname) elif isinstance(data, np.ndarray): logger.info( info_ndarr(data, 'switch to Image Viewer to view data:')) self.set_tab(tabname='Image') elif isinstance(data, str): logger.info(info_ndarr(data, 'switch to Text Viewer to view data:')) self.set_tab(tabname='Text') elif isinstance(data, dict): from psana.pscalib.calib.MDBConvertUtils import info_dict logger.info( 'data is dict switch to Text Viewer to view data as info_dict') cp.last_selected_data = info_dict( data, offset=' ', s='') #str(cp.last_selected_data) self.set_tab(tabname='Text') else: logger.debug( 'data of the selected document is not numpy array - do not switch to Image Viewer' ) cp.last_selected_data = None def set_tab(self, tabname='Image'): logger.debug('switch tab to %s' % str(tabname)) self.tab_bar.setCurrentIndex(self.tab_names.index(tabname)) def key_usage(self): return 'Keys:'\ '\n V - view/hide tabs'\ '\n' if __name__ == "__main__": def keyPressEvent(self, e): #logger.debug('keyPressEvent, key=%s' % e.key()) if e.key() == Qt.Key_Escape: self.close() elif e.key() == Qt.Key_V: self.view_hide_tabs() else: logger.debug(self.key_usage())
class MainWindow(QMainWindow): def __init__(self, doc): QMainWindow.__init__(self, None) self.doc = doc self.app = doc.app self._setupUi() # Create base elements self.model = MainWindowModel(document=doc.model) self.model2view = {} self.alookup = Lookup(self, model=self.model.account_lookup) self.clookup = Lookup(self, model=self.model.completion_lookup) self.drsel = DateRangeSelector(mainwindow=self, view=self.dateRangeSelectorView) self.sfield = SearchField(model=self.model.search_field, view=self.searchLineEdit) self.importWindow = ImportWindow(self) self.csvOptionsWindow = CSVOptionsWindow(self) self.recentDocuments = Recent(self.app, 'recentDocuments') self.recentDocuments.addMenu(self.menuOpenRecent) self.model.view = self self.model.connect() self._updateUndoActions() self._bindSignals() def _setupUi(self): # has to take place *before* base elements creation self.setWindowTitle("moneyGuru") self.resize(700, 580) self.centralwidget = QWidget(self) self.verticalLayout = QVBoxLayout(self.centralwidget) self.verticalLayout.setSpacing(0) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.topBar = QWidget(self.centralwidget) self.horizontalLayout_2 = QHBoxLayout(self.topBar) self.horizontalLayout_2.setContentsMargins(2, 0, 2, 0) spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem) self.dateRangeSelectorView = DateRangeSelectorView(self.topBar) self.dateRangeSelectorView.setMinimumSize(QSize(220, 0)) self.horizontalLayout_2.addWidget(self.dateRangeSelectorView) spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem1) self.searchLineEdit = SearchEdit(self.topBar) self.searchLineEdit.setMaximumSize(QSize(240, 16777215)) self.horizontalLayout_2.addWidget(self.searchLineEdit) self.verticalLayout.addWidget(self.topBar) self.tabBar = QTabBar(self.centralwidget) self.tabBar.setMinimumSize(QSize(0, 20)) self.verticalLayout.addWidget(self.tabBar) self.mainView = QStackedWidget(self.centralwidget) self.verticalLayout.addWidget(self.mainView) # Bottom buttons & status label self.bottomBar = QWidget(self.centralwidget) self.horizontalLayout = QHBoxLayout(self.bottomBar) self.horizontalLayout.setContentsMargins(2, 2, 2, 2) self.horizontalLayout.setContentsMargins(0, 0, 0, 0) self.newItemButton = QPushButton(self.bottomBar) buttonSizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed) buttonSizePolicy.setHorizontalStretch(0) buttonSizePolicy.setVerticalStretch(0) buttonSizePolicy.setHeightForWidth(self.newItemButton.sizePolicy().hasHeightForWidth()) self.newItemButton.setSizePolicy(buttonSizePolicy) self.newItemButton.setIcon(QIcon(QPixmap(':/plus_8'))) self.horizontalLayout.addWidget(self.newItemButton) self.deleteItemButton = QPushButton(self.bottomBar) self.deleteItemButton.setSizePolicy(buttonSizePolicy) self.deleteItemButton.setIcon(QIcon(QPixmap(':/minus_8'))) self.horizontalLayout.addWidget(self.deleteItemButton) self.editItemButton = QPushButton(self.bottomBar) self.editItemButton.setSizePolicy(buttonSizePolicy) self.editItemButton.setIcon(QIcon(QPixmap(':/info_gray_12'))) self.horizontalLayout.addWidget(self.editItemButton) self.horizontalLayout.addItem(horizontalSpacer(size=20)) self.graphVisibilityButton = QPushButton() self.graphVisibilityButton.setSizePolicy(buttonSizePolicy) self.graphVisibilityButton.setIcon(QIcon(QPixmap(':/graph_visibility_on_16'))) self.horizontalLayout.addWidget(self.graphVisibilityButton) self.piechartVisibilityButton = QPushButton() self.piechartVisibilityButton.setSizePolicy(buttonSizePolicy) self.piechartVisibilityButton.setIcon(QIcon(QPixmap(':/piechart_visibility_on_16'))) self.horizontalLayout.addWidget(self.piechartVisibilityButton) self.columnsVisibilityButton = QPushButton() self.columnsVisibilityButton.setSizePolicy(buttonSizePolicy) self.columnsVisibilityButton.setIcon(QIcon(QPixmap(':/columns_16'))) self.horizontalLayout.addWidget(self.columnsVisibilityButton) self.statusLabel = QLabel(tr("Status")) self.statusLabel.setAlignment(Qt.AlignCenter) self.horizontalLayout.addWidget(self.statusLabel) self.verticalLayout.addWidget(self.bottomBar) self.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(self) self.menubar.setGeometry(QRect(0, 0, 700, 20)) self.menuFile = QMenu(tr("File")) self.menuOpenRecent = QMenu(tr("Open Recent")) self.menuView = QMenu(tr("View")) self.menuDateRange = QMenu(tr("Date Range")) self.menuEdit = QMenu(tr("Edit")) self.menuHelp = QMenu(tr("Help")) self.setMenuBar(self.menubar) self.actionOpenDocument = QAction(tr("Open..."), self) self.actionOpenDocument.setShortcut("Ctrl+O") self.actionShowNetWorth = QAction(tr("Net Worth"), self) self.actionShowNetWorth.setShortcut("Ctrl+1") self.actionShowNetWorth.setIcon(QIcon(QPixmap(':/balance_sheet_48'))) self.actionShowProfitLoss = QAction(escapeamp(tr("Profit & Loss")), self) self.actionShowProfitLoss.setShortcut("Ctrl+2") self.actionShowProfitLoss.setIcon(QIcon(QPixmap(':/income_statement_48'))) self.actionShowTransactions = QAction(tr("Transactions"), self) self.actionShowTransactions.setShortcut("Ctrl+3") self.actionShowTransactions.setIcon(QIcon(QPixmap(':/transaction_table_48'))) self.actionShowSelectedAccount = QAction(tr("Show Account"), self) self.actionShowSelectedAccount.setShortcut("Ctrl+]") self.actionNewItem = QAction(tr("New Item"), self) self.actionNewItem.setShortcut("Ctrl+N") self.actionDeleteItem = QAction(tr("Remove Selected"), self) self.actionEditItem = QAction(tr("Show Info"), self) self.actionEditItem.setShortcut("Ctrl+I") self.actionToggleGraph = QAction(tr("Toggle Graph"), self) self.actionToggleGraph.setShortcut("Ctrl+Alt+G") self.actionTogglePieChart = QAction(tr("Toggle Pie Chart"), self) self.actionTogglePieChart.setShortcut("Ctrl+Alt+P") self.actionMoveUp = QAction(tr("Move Up"), self) self.actionMoveUp.setShortcut("Ctrl++") self.actionMoveDown = QAction(tr("Move Down"), self) self.actionMoveDown.setShortcut("Ctrl+-") self.actionNavigateBack = QAction(tr("Go Back"), self) self.actionNavigateBack.setShortcut("Ctrl+[") self.actionNewAccountGroup = QAction(tr("New Account Group"), self) self.actionNewAccountGroup.setShortcut("Ctrl+Shift+N") self.actionShowNextView = QAction(tr("Next View"), self) self.actionShowNextView.setShortcut("Ctrl+Shift+]") self.actionShowPreviousView = QAction(tr("Previous View"), self) self.actionShowPreviousView.setShortcut("Ctrl+Shift+[") self.actionNewDocument = QAction(tr("New Document"), self) self.actionOpenExampleDocument = QAction(tr("Open Example Document"), self) self.actionOpenPluginFolder = QAction(tr("Open Plugin Folder"), self) self.actionImport = QAction(tr("Import..."), self) self.actionImport.setShortcut("Ctrl+Alt+I") self.actionExport = QAction(tr("Export..."), self) self.actionExport.setShortcut("Ctrl+Alt+E") self.actionSave = QAction(tr("Save"), self) self.actionSave.setShortcut("Ctrl+S") self.actionSaveAs = QAction(tr("Save As..."), self) self.actionSaveAs.setShortcut("Ctrl+Shift+S") self.actionAbout = QAction(tr("About moneyGuru"), self) self.actionToggleReconciliationMode = QAction(tr("Toggle Reconciliation Mode"), self) self.actionToggleReconciliationMode.setShortcut("Ctrl+Shift+R") self.actionToggleAccountExclusion = QAction(tr("Toggle Exclusion Status of Account"), self) self.actionToggleAccountExclusion.setShortcut("Ctrl+Shift+X") self.actionShowSchedules = QAction(tr("Schedules"), self) self.actionShowSchedules.setShortcut("Ctrl+4") self.actionShowSchedules.setIcon(QIcon(QPixmap(':/schedules_48'))) self.actionShowBudgets = QAction(tr("Budgets"), self) self.actionShowBudgets.setShortcut("Ctrl+5") self.actionShowBudgets.setIcon(QIcon(QPixmap(':/budget_48'))) self.actionReconcileSelected = QAction(tr("Reconcile Selection"), self) self.actionReconcileSelected.setShortcut("Ctrl+R") self.actionMakeScheduleFromSelected = QAction(tr("Make Schedule from Selected"), self) self.actionMakeScheduleFromSelected.setShortcut("Ctrl+M") self.actionShowPreferences = QAction(tr("Preferences..."), self) self.actionPrint = QAction(tr("Print..."), self) self.actionPrint.setShortcut("Ctrl+P") self.actionQuit = QAction(tr("Quit moneyGuru"), self) self.actionQuit.setShortcut("Ctrl+Q") self.actionUndo = QAction(tr("Undo"), self) self.actionUndo.setShortcut("Ctrl+Z") self.actionRedo = QAction(tr("Redo"), self) self.actionRedo.setShortcut("Ctrl+Y") self.actionShowHelp = QAction(tr("moneyGuru Help"), self) self.actionShowHelp.setShortcut("F1") self.actionCheckForUpdate = QAction(tr("Check for update"), self) self.actionOpenDebugLog = QAction(tr("Open Debug Log"), self) self.actionDuplicateTransaction = QAction(tr("Duplicate Transaction"), self) self.actionDuplicateTransaction.setShortcut("Ctrl+D") self.actionJumpToAccount = QAction(tr("Jump to Account..."), self) self.actionJumpToAccount.setShortcut("Ctrl+Shift+A") self.actionNewTab = QAction(tr("New Tab"), self) self.actionNewTab.setShortcut("Ctrl+T") self.actionCloseTab = QAction(tr("Close Tab"), self) self.actionCloseTab.setShortcut("Ctrl+W") self.menuFile.addAction(self.actionNewDocument) self.menuFile.addAction(self.actionNewTab) self.menuFile.addAction(self.actionOpenDocument) self.menuFile.addAction(self.menuOpenRecent.menuAction()) self.menuFile.addAction(self.actionOpenExampleDocument) self.menuFile.addAction(self.actionOpenPluginFolder) self.menuFile.addAction(self.actionImport) self.menuFile.addSeparator() self.menuFile.addAction(self.actionCloseTab) self.menuFile.addAction(self.actionSave) self.menuFile.addAction(self.actionSaveAs) self.menuFile.addAction(self.actionExport) self.menuFile.addAction(self.actionPrint) self.menuFile.addAction(self.actionQuit) self.menuView.addAction(self.actionShowNetWorth) self.menuView.addAction(self.actionShowProfitLoss) self.menuView.addAction(self.actionShowTransactions) self.menuView.addAction(self.actionShowSchedules) self.menuView.addAction(self.actionShowBudgets) self.menuView.addAction(self.actionShowPreviousView) self.menuView.addAction(self.actionShowNextView) self.menuView.addAction(self.menuDateRange.menuAction()) self.menuView.addAction(self.actionShowPreferences) self.menuView.addAction(self.actionToggleGraph) self.menuView.addAction(self.actionTogglePieChart) self.menuEdit.addAction(self.actionNewItem) self.menuEdit.addAction(self.actionNewAccountGroup) self.menuEdit.addAction(self.actionDeleteItem) self.menuEdit.addAction(self.actionEditItem) self.menuEdit.addSeparator() self.menuEdit.addAction(self.actionMoveUp) self.menuEdit.addAction(self.actionMoveDown) self.menuEdit.addAction(self.actionDuplicateTransaction) self.menuEdit.addAction(self.actionMakeScheduleFromSelected) self.menuEdit.addAction(self.actionReconcileSelected) self.menuEdit.addAction(self.actionToggleReconciliationMode) self.menuEdit.addAction(self.actionToggleAccountExclusion) self.menuEdit.addSeparator() self.menuEdit.addAction(self.actionShowSelectedAccount) self.menuEdit.addAction(self.actionNavigateBack) self.menuEdit.addAction(self.actionJumpToAccount) self.menuEdit.addSeparator() self.menuEdit.addAction(self.actionUndo) self.menuEdit.addAction(self.actionRedo) self.menuHelp.addAction(self.actionShowHelp) self.menuHelp.addAction(self.actionCheckForUpdate) self.menuHelp.addAction(self.actionOpenDebugLog) self.menuHelp.addAction(self.actionAbout) mainmenus = [self.menuFile, self.menuEdit, self.menuView, self.menuHelp] for menu in mainmenus: self.menubar.addAction(menu.menuAction()) setAccelKeys(menu) setAccelKeys(self.menubar) self.tabBar.setMovable(True) self.tabBar.setTabsClosable(True) self.tabBar.setExpanding(False) seq = QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Right) self._shortcutNextTab = QShortcut(seq, self) seq = QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Left) self._shortcutPrevTab = QShortcut(seq, self) # Linux setup if ISLINUX: self.actionCheckForUpdate.setVisible(False) # This only works on Windows def _bindSignals(self): self.newItemButton.clicked.connect(self.actionNewItem.trigger) self.deleteItemButton.clicked.connect(self.actionDeleteItem.trigger) self.editItemButton.clicked.connect(self.actionEditItem.trigger) self.graphVisibilityButton.clicked.connect(self.actionToggleGraph.trigger) self.piechartVisibilityButton.clicked.connect(self.actionTogglePieChart.trigger) self.columnsVisibilityButton.clicked.connect(self.columnsVisibilityButtonClicked) self.recentDocuments.mustOpenItem.connect(self.doc.open) self.doc.documentOpened.connect(self.recentDocuments.insertItem) self.doc.documentSavedAs.connect(self.recentDocuments.insertItem) self.doc.documentPathChanged.connect(self.documentPathChanged) self.tabBar.currentChanged.connect(self.currentTabChanged) self.tabBar.tabCloseRequested.connect(self.tabCloseRequested) self.tabBar.tabMoved.connect(self.tabMoved) # Views self.actionShowNetWorth.triggered.connect(self.showNetWorthTriggered) self.actionShowProfitLoss.triggered.connect(self.showProfitLossTriggered) self.actionShowTransactions.triggered.connect(self.showTransactionsTriggered) self.actionShowSchedules.triggered.connect(self.showSchedulesTriggered) self.actionShowBudgets.triggered.connect(self.showBudgetsTriggered) self.actionShowPreviousView.triggered.connect(self.showPreviousViewTriggered) self.actionShowNextView.triggered.connect(self.showNextViewTriggered) self.actionShowPreferences.triggered.connect(self.app.showPreferences) self.actionToggleGraph.triggered.connect(self.toggleGraphTriggered) self.actionTogglePieChart.triggered.connect(self.togglePieChartTriggered) # Document Edition self.actionNewItem.triggered.connect(self.newItemTriggered) self.actionNewAccountGroup.triggered.connect(self.newAccountGroupTriggered) self.actionDeleteItem.triggered.connect(self.deleteItemTriggered) self.actionEditItem.triggered.connect(self.editItemTriggered) self.actionMoveUp.triggered.connect(self.moveUpTriggered) self.actionMoveDown.triggered.connect(self.moveDownTriggered) self.actionDuplicateTransaction.triggered.connect(self.model.duplicate_item) self.actionUndo.triggered.connect(self.doc.model.undo) self.actionRedo.triggered.connect(self.doc.model.redo) # Open / Save / Import / Export / New self.actionNewDocument.triggered.connect(self.doc.new) self.actionOpenDocument.triggered.connect(self.doc.openDocument) self.actionOpenExampleDocument.triggered.connect(self.doc.openExampleDocument) self.actionOpenPluginFolder.triggered.connect(self.model.app.open_plugin_folder) self.actionImport.triggered.connect(self.importDocument) self.actionSave.triggered.connect(self.doc.save) self.actionSaveAs.triggered.connect(self.doc.saveAs) self.actionExport.triggered.connect(self.model.export) # Misc self.actionNewTab.triggered.connect(self.model.new_tab) self.actionCloseTab.triggered.connect(self.closeTabTriggered) self.actionShowSelectedAccount.triggered.connect(self.model.show_account) self.actionNavigateBack.triggered.connect(self.navigateBackTriggered) self.actionJumpToAccount.triggered.connect(self.jumpToAccountTriggered) self.actionMakeScheduleFromSelected.triggered.connect(self.makeScheduleFromSelectedTriggered) self.actionReconcileSelected.triggered.connect(self.reconcileSelectedTriggered) self.actionToggleReconciliationMode.triggered.connect(self.toggleReconciliationModeTriggered) self.actionToggleAccountExclusion.triggered.connect(self.toggleAccountExclusionTriggered) self.actionPrint.triggered.connect(self._print) self.actionShowHelp.triggered.connect(self.app.showHelp) self.actionCheckForUpdate.triggered.connect(self.checkForUpdateTriggered) self.actionAbout.triggered.connect(self.aboutTriggered) self.actionOpenDebugLog.triggered.connect(self.openDebugLogTriggered) self.actionQuit.triggered.connect(self.close) # Extra Shortcuts self._shortcutNextTab.activated.connect(self.showNextViewTriggered) self._shortcutPrevTab.activated.connect(self.showPreviousViewTriggered) # --- QWidget overrides def closeEvent(self, event): if self.doc.confirmDestructiveAction(): event.accept() else: event.ignore() # --- Private def _print(self): dialog = QPrintDialog(self) if dialog.exec_() != QPrintDialog.Accepted: return printer = dialog.printer() currentView = self.mainView.currentWidget() viewPrinter = ViewPrinter(printer, currentView) currentView.fitViewsForPrint(viewPrinter) viewPrinter.render() def _getViewforPane(self, pane_type, pane_view): if pane_view in self.model2view: view = self.model2view[pane_view] else: view = PANETYPE2VIEWCLASS[pane_type](model=pane_view, mainwindow=self) self.model2view[pane_view] = view self.mainView.addWidget(view) view.restoreSubviewsSize() return view def _setTabIndex(self, index): if not self.tabBar.count(): return self.tabBar.setCurrentIndex(index) self._updateActionsState() pane_type = self.model.pane_type(index) pane_view = self.model.pane_view(index) view = self._getViewforPane(pane_type, pane_view) self.mainView.setCurrentWidget(view) view.setFocus() def _activeView(self): paneIndex = self.model.current_pane_index return self.model.pane_view(paneIndex) def _updateActionsState(self): # Updates enable/disable checked/unchecked state of all actions. These state can change # under various conditions: main view change, date range type change and when reconciliation # mode is toggled # Determine what actions are enabled view = self._activeView() viewType = view.VIEW_TYPE isSheet = viewType in {PaneType.NetWorth, PaneType.Profit} isTransactionOrEntryTable = viewType in {PaneType.Transaction, PaneType.Account} canToggleReconciliation = viewType == PaneType.Account and view.can_toggle_reconciliation_mode newItemLabel = { PaneType.NetWorth: tr("New Account"), PaneType.Profit: tr("New Account"), PaneType.Transaction: tr("New Transaction"), PaneType.Account: tr("New Transaction"), PaneType.Schedule: tr("New Schedule"), PaneType.Budget: tr("New Budget"), PaneType.GeneralLedger: tr("New Transaction"), }.get(viewType, tr("New Item")) # XXX make "New Item" disabled self.actionNewItem.setText(newItemLabel) self.actionNewAccountGroup.setEnabled(isSheet) self.actionMoveDown.setEnabled(isTransactionOrEntryTable) self.actionMoveUp.setEnabled(isTransactionOrEntryTable) self.actionDuplicateTransaction.setEnabled(isTransactionOrEntryTable) self.actionMakeScheduleFromSelected.setEnabled(isTransactionOrEntryTable) self.actionReconcileSelected.setEnabled(viewType == PaneType.Account and view.reconciliation_mode) self.actionShowNextView.setEnabled(self.model.current_pane_index < self.model.pane_count-1) self.actionShowPreviousView.setEnabled(self.model.current_pane_index > 0) self.actionShowSelectedAccount.setEnabled(isSheet or isTransactionOrEntryTable) self.actionNavigateBack.setEnabled(viewType == PaneType.Account) self.actionToggleReconciliationMode.setEnabled(canToggleReconciliation) self.actionToggleAccountExclusion.setEnabled(isSheet) def _updateUndoActions(self): if self.doc.model.can_undo(): self.actionUndo.setEnabled(True) self.actionUndo.setText(tr("Undo {0}").format(self.doc.model.undo_description())) else: self.actionUndo.setEnabled(False) self.actionUndo.setText(tr("Undo")) if self.doc.model.can_redo(): self.actionRedo.setEnabled(True) self.actionRedo.setText(tr("Redo {0}").format(self.doc.model.redo_description())) else: self.actionRedo.setEnabled(False) self.actionRedo.setText(tr("Redo")) # --- Actions # Views def showNetWorthTriggered(self): self.model.select_pane_of_type(PaneType.NetWorth) def showProfitLossTriggered(self): self.model.select_pane_of_type(PaneType.Profit) def showTransactionsTriggered(self): self.model.select_pane_of_type(PaneType.Transaction) def showSchedulesTriggered(self): self.model.select_pane_of_type(PaneType.Schedule) def showBudgetsTriggered(self): self.model.select_pane_of_type(PaneType.Budget) def showPreviousViewTriggered(self): self.model.select_previous_view() def showNextViewTriggered(self): self.model.select_next_view() # Document Edition def newItemTriggered(self): self.model.new_item() def newAccountGroupTriggered(self): self.model.new_group() def deleteItemTriggered(self): self.model.delete_item() def editItemTriggered(self): self.model.edit_item() def moveUpTriggered(self): self.model.move_up() def moveDownTriggered(self): self.model.move_down() # Misc def closeTabTriggered(self): self.model.close_pane(self.model.current_pane_index) def navigateBackTriggered(self): self.model.navigate_back() def jumpToAccountTriggered(self): self.model.jump_to_account() def makeScheduleFromSelectedTriggered(self): self.model.make_schedule_from_selected() def reconcileSelectedTriggered(self): self._activeView().etable.toggle_reconciled() def toggleReconciliationModeTriggered(self): self._activeView().toggle_reconciliation_mode() self._updateActionsState() def toggleAccountExclusionTriggered(self): viewType = self.model.pane_type(self.model.current_pane_index) if viewType in {PaneType.NetWorth, PaneType.Profit}: self._activeView().sheet.toggle_excluded() def toggleGraphTriggered(self): self.model.toggle_area_visibility(PaneArea.BottomGraph) def togglePieChartTriggered(self): self.model.toggle_area_visibility(PaneArea.RightChart) def columnsVisibilityButtonClicked(self): items = self.model.column_menu_items() if not items: return menu = QMenu() for i, (display, marked) in enumerate(items): action = menu.addAction(display) action.setCheckable(True) action.setChecked(marked) action.setData(i) action.triggered.connect(self.columnsMenuItemWasClicked) self._columnMenuHolder = menu # we need to hold a reference to it while it popups button = self.columnsVisibilityButton menu.popup(button.parentWidget().mapToGlobal(button.geometry().topLeft())) def columnsMenuItemWasClicked(self): action = self.sender() if action is not None: index = action.data() self.model.toggle_column_menu_item(index) def checkForUpdateTriggered(self): QProcess.execute('updater.exe', ['/checknow']) def aboutTriggered(self): self.app.showAboutBox() def openDebugLogTriggered(self): debugLogPath = op.join(getAppData(), 'debug.log') url = QUrl.fromLocalFile(debugLogPath) QDesktopServices.openUrl(url) def importDocument(self): title = tr("Select a document to import") filters = tr("Supported files (*.moneyguru *.ofx *.qfx *.qif *.csv *.txt)") docpath, filetype = QFileDialog.getOpenFileName(self.app.mainWindow, title, '', filters) # There's a strange glitch under GNOME where, right after the dialog is gone, the main # window isn't the active window, but it will become active if we give it enough time. If we # start showing the import window before that happens, we'll end up with an import window # under the main window, which is bad. Therefore, we process events until this happens. We # do this in a big forloop instead of a while to avoid a possible infinite loop. for i in range(10000): if self.app.mainWindow.isActiveWindow(): break QApplication.processEvents() if docpath: try: self.model.parse_file_for_import(docpath) except FileFormatError as e: QMessageBox.warning(self.app.mainWindow, tr("Cannot import file"), str(e)) # --- Other Signals def currentTabChanged(self, index): self.model.current_pane_index = index self._setTabIndex(index) def documentPathChanged(self): if self.doc.documentPath: title = "moneyGuru ({})".format(self.doc.documentPath) else: title = "moneyGuru" self.setWindowTitle(title) def tabCloseRequested(self, index): self.model.close_pane(index) def tabMoved(self, fromIndex, toIndex): self.model.move_pane(fromIndex, toIndex) # --- model --> view def change_current_pane(self): self._setTabIndex(self.model.current_pane_index) def get_panel_view(self, model): if isinstance(model, CustomDateRangePanelModel): return CustomDateRangePanel(model, self) else: return ExportPanel(model, self) def refresh_panes(self): # Always remove the "new tab" tab if self.tabBar.count() > 0: self.tabBar.removeTab(self.tabBar.count()-1) while self.tabBar.count() < self.model.pane_count: self.tabBar.addTab('') for i in range(self.model.pane_count): pane_label = self.model.pane_label(i) pane_label = escapeamp(pane_label) self.tabBar.setTabText(i, pane_label) pane_type = self.model.pane_type(i) pane_view = self.model.pane_view(i) # Ensure that the view's "view" has been created and bound self._getViewforPane(pane_type, pane_view) iconname = PANETYPE2ICON.get(pane_type) icon = QIcon(QPixmap(':/{0}'.format(iconname))) if iconname else QIcon() self.tabBar.setTabIcon(i, icon) # It's important that we proceed with tab removal *after* we've completed tab initialization. # We're walking on eggshells here. refresh_panes() can be called in multiple situations, one # of them is during the opening of a document. When that happens when another document was # previously opened, all views' model are uninitalized and don't have their "view" attribute # set yet. If we proceed with the setCurrentIndex() call below before _getViewforPane() # could be called above, we get a crash. if self.tabBar.currentIndex() >= self.model.pane_count: # Normally, we don't touch the tabBar index here and wait for change_current_pane, # but when we remove tabs, it's possible that currentTabChanged end up being called and # then the tab selection is bugged. I tried disconnecting/reconnecting the signal, but # this is buggy. So when a selected tab is about to be removed and is out of bounds, # we change the selection to the last index in the model. We don't use # self.model.current_pane_index because in some cases, it's -1 and prevents this crash # preventer from preventing its crash. self.tabBar.setCurrentIndex(self.model.pane_count - 1) while self.tabBar.count() > self.model.pane_count: self.tabBar.removeTab(self.tabBar.count()-1) self.tabBar.setTabsClosable(self.model.pane_count > 1) # Add the "new tab" tab last_tab_index = self.tabBar.addTab('') self.tabBar.setTabEnabled(last_tab_index, False) newTabButton = QToolButton() newTabButton.setText("+") newTabButton.clicked.connect(self.model.new_tab) self.tabBar.setTabButton(last_tab_index, QTabBar.RightSide, newTabButton) def refresh_status_line(self): self.statusLabel.setText(self.model.status_line) def refresh_undo_actions(self): self._updateUndoActions() def restore_window_frame(self, frame): self.setGeometry(*frame) def save_window_frame(self): r = self.geometry() return (r.x(), r.y(), r.width(), r.height()) def show_message(self, msg): title = tr("Warning") QMessageBox.warning(self, title, msg) def update_area_visibility(self): hidden = self.model.hidden_areas graphimg = ':/graph_visibility_{}_16'.format('off' if PaneArea.BottomGraph in hidden else 'on') pieimg = ':/piechart_visibility_{}_16'.format('off' if PaneArea.RightChart in hidden else 'on') self.graphVisibilityButton.setIcon(QIcon(QPixmap(graphimg))) self.piechartVisibilityButton.setIcon(QIcon(QPixmap(pieimg))) def view_closed(self, index): self.tabBar.removeTab(index) self.tabBar.setTabsClosable(self.model.pane_count > 1)
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)
class App(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Qt-browser") self.setMinimumSize(1366, 768) self.CreateApp() def CreateApp(self): self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0, 0, 0, 0) # create tabs self.tabbar = QTabBar(movable=True, tabsClosable=True) self.tabbar.tabCloseRequested.connect(self.CloseTab) self.tabbar.tabBarClicked.connect(self.SwitchTab) self.tabbar.setCurrentIndex(0) # keep track of all tabs self.tabCount = 0 self.tabs = [] # create address bar self.Toolbar = QWidget() self.ToolbarLayout = QHBoxLayout() self.AddressBar = AddressBar() self.AddressBar.returnPressed.connect(self.BrowseTo) # create new tab button self.AddTabButton = QPushButton("+") self.AddTabButton.clicked.connect(self.AddTab) # create functional buttons - back, forward and reload self.BackButton = QPushButton("<") self.BackButton.clicked.connect(self.GoBack) self.ForwardButton = QPushButton(">") self.ForwardButton.clicked.connect(self.GoForward) self.ReloadButton = QPushButton("R") self.ReloadButton.clicked.connect(self.ReloadPage) # append toolbar and buttons self.Toolbar.setLayout(self.ToolbarLayout) self.ToolbarLayout.addWidget(self.BackButton) self.ToolbarLayout.addWidget(self.ForwardButton) self.ToolbarLayout.addWidget(self.ReloadButton) self.ToolbarLayout.addWidget(self.AddressBar) self.ToolbarLayout.addWidget(self.AddTabButton) # set main view self.Container = QWidget() self.Container.Layout = QStackedLayout() self.Container.setLayout(self.Container.Layout) self.layout.addWidget(self.tabbar) self.layout.addWidget(self.Toolbar) self.layout.addWidget(self.Container) self.setLayout(self.layout) self.show() def CloseTab(self, i): self.tabbar.removeTab(i) self.tabCount -= 1 def AddTab(self): i = self.tabCount self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].layout.setContentsMargins(0,0,0,0) # tab switching self.tabs[i].setObjectName("tab" + str(self.tabCount)) # open web view self.tabs[i].content = QWebEngineView() self.tabs[i].content.load(QUrl.fromUserInput("http://google.com")) self.tabs[i].content.titleChanged.connect(lambda: self.SetTabContent(i, "title")) self.tabs[i].content.iconChanged.connect(lambda: self.SetTabContent(i, "icon")) self.tabs[i].content.urlChanged.connect(lambda: self.SetTabContent(i, "url")) # add web view to tabs layout self.tabs[i].layout.addWidget(self.tabs[i].content) # set top level tab from [] to layout self.tabs[i].setLayout(self.tabs[i].layout) # add tab to top level stackedwidget self.Container.Layout.addWidget(self.tabs[i]) self.Container.Layout.setCurrentWidget(self.tabs[i]) # set the tab at the top of screen self.tabbar.addTab("new tab") self.tabbar.setTabData(i, {"object": "tab" + str(i), "initial": i}) self.tabbar.setCurrentIndex(i) self.tabCount += 1 def SwitchTab(self, i): tab_data = self.tabbar.tabData(i)["object"] tab_widget = self.findChild(QWidget, tab_data) self.Container.Layout.setCurrentWidget(tab_widget) new_url = tab_widget.content.url().toString() self.AddressBar.setText(new_url) def BrowseTo(self): address_text = self.AddressBar.text() i = self.tabbar.currentIndex() print(i) #TODO - better check if any tab exists before accessing it if i < 0: self.AddTab() i = 0 else: pass print(i) tab = self.tabbar.tabData(i)["object"] web_view = self.findChild(QWidget, tab).content #TODO - find a better way to filter string passed in address bar if "http" not in address_text: if "." not in address_text: url = "https://www.google.pl/#q=" + address_text else: url = "http://" + address_text else: url = address_text print(url) web_view.load(QUrl.fromUserInput(url)) def SetTabContent(self, i, type): tab_name = self.tabs[i].objectName() count = 0 running = True current_tab = self.tabbar.tabData(self.tabbar.currentIndex())["object"] if current_tab == tab_name and type == "url": new_url = self.findChild(QWidget, tab_name).content.url().toString() self.AddressBar.setText(new_url) while running: tab_data_name = self.tabbar.tabData(count) if count >= 99: running = False if tab_name == tab_data_name["object"]: if type == "title": new_title = self.findChild(QWidget, tab_name).content.title() self.tabbar.setTabText(count, new_title) elif type == "icon": new_icon = self.findChild(QWidget, tab_name).content.icon() self.tabbar.setTabIcon(count, new_icon) running = False else: count += 1 def GoBack(self): active_index = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(active_index)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.back() def GoForward(self): active_index = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(active_index)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.forward() def ReloadPage(self): active_index = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(active_index)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.reload()
class App(QFrame): def __init__(self): super().__init__() self.setWindowTitle("Web Browser") self.setBaseSize(1366, 768) self.setMinimumSize(1366, 768) self.setWindowIcon(QIcon("logo.png")) self.CreateApp() def CreateApp(self): self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(0,0,0,0) # Create Tabs self.tabbar = QTabBar(movable=True, tabsClosable=True) self.tabbar.tabCloseRequested.connect(self.CloseTab) self.tabbar.tabBarClicked.connect(self.SwitchTab) self.tabbar.setCurrentIndex(0) self.tabbar.setDrawBase(False) # Create a shortcut key for a new tab self.shortcutNewTab = QShortcut(QKeySequence("Ctrl+T"), self) self.shortcutNewTab.activated.connect(self.AddTab) # keep track of tabs self.tabCount = 0 self.tabs = [] # Create Addressbar self.Toolbar = QWidget() self.Toolbar.setObjectName("Toolbar") self.ToolbarLayout = QHBoxLayout() self.addressbar = AddressBar() self.AddTabButton = QPushButton("+") # Connect Addressbar + button signals self.addressbar.returnPressed.connect(self.BrowseTo) self.AddTabButton.clicked.connect(self.AddTab) # set toolbar buttons and signals self.BackButton = QPushButton("<") self.BackButton.clicked.connect(self.GoBack) self.ForwardButton = QPushButton(">") self.ForwardButton.clicked.connect(self.GoForward) self.ReloadButton = QPushButton("↻") self.ReloadButton.clicked.connect(self.GoReload) # Build toolbar self.Toolbar.setLayout(self.ToolbarLayout) self.ToolbarLayout.addWidget(self.BackButton) self.ToolbarLayout.addWidget(self.ForwardButton) self.ToolbarLayout.addWidget(self.ReloadButton) self.ToolbarLayout.addWidget(self.addressbar) self.ToolbarLayout.addWidget(self.AddTabButton) # set main view self.container = QWidget() self.container.layout = QStackedLayout() self.container.setLayout(self.container.layout) # construct main view self.layout.addWidget(self.tabbar) self.layout.addWidget(self.Toolbar) self.layout.addWidget(self.container) self.setLayout(self.layout) self.AddTab() self.show() def CloseTab(self, i): self.tabbar.removeTab(i) def AddTab(self): i = self.tabCount # set self.tabs<#> = QWidget self.tabs.append(QWidget()) self.tabs[i].layout = QVBoxLayout() self.tabs[i].layout.setContentsMargins(0,0,0,0) # For tab switching self.tabs[i].setObjectName("tab" + str(i)) # create the web engine view self.tabs[i].content = QWebEngineView() self.tabs[i].content.load(QUrl.fromUserInput("http://bing.com")) self.tabs[i].content.titleChanged.connect(lambda: self.SetTabContent(i, "title")) self.tabs[i].content.iconChanged.connect(lambda: self.SetTabContent(i, "icon")) self.tabs[i].content.urlChanged.connect(lambda: self.SetTabContent(i, "url")) # add widget to tabs layout self.tabs[i].layout.addWidget(self.tabs[i].content) # set top level tab from list to layout self.tabs[i].setLayout(self.tabs[i].layout) # add tab to top level stacked widget self.container.layout.addWidget(self.tabs[i]) self.container.layout.setCurrentWidget(self.tabs[i]) # create tab on tabbar, representing this tab # set tabData to tab<#> so it knows what self.tabs[#] it needs to control self.tabbar.addTab("New Tab") self.tabbar.setTabData(i, {"object": "tab" + str(i), "initial": i}) self.tabbar.setCurrentIndex(i) self.tabCount += 1 print(self.tabCount) def SwitchTab(self, i): if self.tabbar.tabData(i): tab_data = self.tabbar.tabData(i)["object"] print(tab_data) tab_content = self.findChild(QWidget, tab_data) self.container.layout.setCurrentWidget(tab_content) new_url = tab_content.content.url().toString() self.addressbar.setText(new_url) def BrowseTo(self): text = self.addressbar.text() i = self.tabbar.currentIndex() tab = self.tabbar.tabData(i)["object"] wv = self.findChild(QWidget, tab).content if "http" not in text: if "." not in text: url = "https://www.bing.com/search?q=" + text else: url = "http://" + text else: url = text wv.load(QUrl.fromUserInput(url)) def SetTabContent(self, i, type): ''' self.tabs[i].objectName = tab1 self.tabbar.tabData(i)["object"] = tab1 ''' tab_name = self.tabs[i].objectName() count = 0 running = True current_tab = self.tabbar.tabData(self.tabbar.currentIndex())["object"] if current_tab == tab_name and type == "url": new_url = self.findChild(QWidget, tab_name).content.url().toString() self.addressbar.setText(new_url) return False while running: tab_data_name = self.tabbar.tabData(count) if count >= 99: running = False if tab_name == tab_data_name["object"]: if type == "title": newTitle = self.findChild(QWidget, tab_name).content.title() self.tabbar.setTabText(count, newTitle) elif type == "icon": newIcon = self.findChild(QWidget, tab_name).content.icon() self.tabbar.setTabIcon(count, newIcon) running = False else: count += 1 def GoBack(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.back() def GoForward(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.forward() def GoReload(self): activeIndex = self.tabbar.currentIndex() tab_name = self.tabbar.tabData(activeIndex)["object"] tab_content = self.findChild(QWidget, tab_name).content tab_content.reload()
__author__ = 'tim' from PyQt5.QtWidgets import QApplication,QTabBar import sys app=QApplication(sys.argv) TabBar=QTabBar() TabBar.addTab('Food') TabBar.addTab('Drink') TabBar.show() sys.exit(app.exec_())