class EditTaskDialog(QDialog): def __init__(self, parent=None): super(EditTaskDialog, self).__init__(parent) self.setWindowTitle("Edit task") self.parent = parent self.tabWidget = TabWidget() self.tabWidget.setFont(QFont("Moon", 8, QFont.Bold)) path = self.parent.parent.parent.parent.path self.dueDateWidget = DueDateWidget(self) self.dueDateWidget.saveDateBtn.clicked.connect(self.parent.getNewDate) self.tagWidget = TagWidget(self) #self.tagWidget.saveTagBtn.clicked.connect(self.parent.addTagLabel) self.editTaskTitleDialog = CustomDialog(self, 'Edit task title', 'Task name: ', 'Save') self.editTaskTitleDialog.setContentsMargins(10, 40, 10, 40) self.editTaskTitleDialog.button.clicked.connect( self.handleEditTaskTitleBtn) self.memberWidget = MemberWidget(self) self.tabWidget.addTab(self.editTaskTitleDialog, QIcon(path + '\\editDialog.png'), " Edit") self.tabWidget.addTab(self.dueDateWidget, QIcon(path + '\\calendar.png'), " Due date") self.tabWidget.addTab(self.tagWidget, QIcon(path + '\\tag.png'), " Tags") self.tabWidget.addTab(self.memberWidget, QIcon(path + '\\multiple.png'), " Members") self.mainEditTask = QVBoxLayout() self.mainEditTask.addWidget(self.tabWidget) self.setFixedSize(400, 300) self.setLayout(self.mainEditTask) def setColor(self): self.palette = QPalette() self.setAutoFillBackground(True) self.palette.setColor(QPalette.Window, QColor('#FAE76E')) self.setPalette(self.palette) def handleEditTaskTitleBtn(self): if not self.parent.validateNewTaskTitle(): return newTaskTitle = self.parent.getNewTaskTitle() self.parent.setTaskTitle(newTaskTitle) self.parent.parent.parent.parent.editTaskTitle( self.parent.taskId, self.parent.getTaskTitle())
class MainWindow(Systray): def __init__(self, app): """ Create a main window for the given application. """ defaultOptions["palette"] = app.palette() Systray.__init__(self) self.expansions = 0 self.client = None self.server = None self.running = False self.recovery = False mainWidgets["main"] = self mainWidgets["app"] = app self.canvas = Canvas(self) mainWidgets["canvas"] = self.canvas self.tabWidget = TabWidget(self) mainWidgets["tab"] = self.tabWidget self.setCentralWidget(self.tabWidget) #self.setCentralWidget(self.canvas) self.createActions() self.createMenus() self.createToolBars() self.createStatusBar() self.createDockWindows() self.createConfigWindows() self.createPopupWindows() self.createProgressBar() self.newScene() self.debugWindow.hide() self.tm.hide() self.routes.hide() self.setVisible(True) self.center() self.saveLayout(environ["config"] + "defaultLayout") self.defaultLayout = True if options["restore"]: self.loadLayout() self.defaultLayout = False self.loadProject() def center(self): """ Center the window. """ screen = QtGui.QDesktopWidget().screenGeometry() rect = self.geometry() self.move((screen.width()-rect.width())/2, (screen.height()-rect.height())/2) self.show() def getProject(self): """ Return the project. """ return self.project def startTutorial(self): """ Start the interactive tutorial. """ if isinstance(mainWidgets["canvas"], Tutorial): self.log.append("You are already doing the tutorial! If you would like to stop or restart, select 'Close' from the File menu now.") return if not self.closeTopology(): return self.project = "Tutorial" self.filename = "" self.canvas = Tutorial(self) mainWidgets["canvas"] = self.canvas self.tabWidget.removeTab(0) self.tabWidget.addTab(self.canvas, "Tutorial") self.canvas.start() for nodeType in nodeTypes.keys(): itemTypes = nodeTypes[nodeType] itemTypes[nodeType] = 0 self.properties.clear() self.interfaces.clear() self.routes.clear() self.resetLayout(True) self.lockDocks() def lockDocks(self): """ Lock the dock windows so they cannot be moved, closed or resized. """ self.tm.hide() for dock in self.docks.values(): dock.setFeatures(dock.NoDockWidgetFeatures) def unlockDocks(self): """ Unlock the dock windows. """ self.tm.show() for dock in self.docks.values(): dock.setFeatures(dock.DockWidgetClosable | dock.DockWidgetMovable | dock.DockWidgetFloatable) def faq(self): """ Open the FAQ in the default browser. """ olddir = os.getcwd() os.chdir(environ["doc"]) loadpath = os.getcwd() os.chdir(olddir) if environ["os"] == "Windows": url = QtCore.QUrl("file:///" + loadpath + "/FAQ.html") else: url = QtCore.QUrl("file://" + loadpath + "/FAQ.html") QtGui.QDesktopServices.openUrl(url) def closeTopology(self): """ Close the current topology. """ if self.running: self.log.append("You cannot close a topology when one is still running!") return False scene = self.canvas.scene() if scene and scene.items(): reply = QtGui.QMessageBox.warning(self, self.tr(Core.globals.PROG_NAME), self.tr("Save before closing?"), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No | QtGui.QMessageBox.Cancel) if reply == QtGui.QMessageBox.Yes: if not self.saveTopology(): return False elif reply == QtGui.QMessageBox.No: pass else: return False if isinstance(mainWidgets["canvas"], Tutorial): self.canvas = Canvas(self) mainWidgets["canvas"] = self.canvas self.tabWidget.removeTab(0) self.tabWidget.addTab(self.canvas, "Default Project") self.project = "" self.unlockDocks() self.filename = "" scene = Scene(self.canvas) scene.setItemIndexMethod(QtGui.QGraphicsScene.NoIndex) self.canvas.setScene(scene) self.expansions = 0 for nodeType in nodeTypes.keys(): itemTypes = nodeTypes[nodeType] itemTypes[nodeType] = 0 self.properties.clear() self.interfaces.clear() self.routes.clear() return True def sendFile(self): """ Start a process to select and send a file to the server. """ if not self.server or self.server.poll() != None: self.log.append("Please start the server first!") return if not self.client or not self.client.isConnected(): self.startClient() filename = self.loadFile("All Files (*.*)") if not filename: return self.sendWindow.setFilename(filename) self.sendWindow.show() def newScene(self): """ Close the current topology and create a new one. """ if self.running: self.log.append("You cannot create a new topology when one is still running!") return if isinstance(mainWidgets["canvas"], Tutorial): self.log.append("You cannot create a new topology during the tutorial!") return if not self.closeTopology(): return self.expandScene() def expandScene(self): """ Expand the scene based on number of expansions. """ x = 175 + self.expansions * 30 y = 160 + self.expansions * 20 scene = self.canvas.scene() item = QtGui.QGraphicsLineItem(-x, -y, x, y) scene.addItem(item) scene.removeItem(item) self.expansions += 1 def newProject(self): """ Create a new project for device sharing. """ if self.running: self.log.append("You cannot create a new project when one is still running!") return if isinstance(mainWidgets["canvas"], Tutorial): self.log.append("You cannot create a new project during the tutorial!") return filename = self.saveFile("gproj") if filename.isEmpty(): return projectname = str(filename).split("/")[-1].strip(".gproj") from Core.Item import nodeTypes for nodeType in nodeTypes: if projectname.startswith(nodeType + "_"): self.popup.setWindowTitle("Invalid Project Name") self.popup.setText("You cannot name a project starting with the name of a device and underscore!") self.popup.show() return self.project = str(filename) file = QtCore.QFile(filename) if not file.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning(self, self.tr("Save Error"), self.tr("Cannot write file %1:\n%2.") .arg(self.filename) .arg(file.errorString())) return out = QtCore.QTextStream(file) QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) if options["username"]: out << "username="******"username"] + "\n" else: self.log.append("Warning, no username is specified!") if options["session"]: out << "session=" + options["session"] + "\n" elif options["server"]: out << "server=" + options["server"] + "\n" else: self.log.append("Warning, no server or session name is specified!") QtGui.QApplication.restoreOverrideCursor() self.tabWidget.addTab(self.canvas, projectname) def openProject(self): """ Load an existing project for device sharing. """ if self.running: self.log.append("You cannot open a project when one is still running!") return if isinstance(mainWidgets["canvas"], Tutorial): self.log.append("You cannot open a project during the tutorial!") return filename = self.loadFile("GPROJ (*.gproj)") if filename.isEmpty(): return self.project = str(filename) self.loadProject() def loadProject(self): """ Load project file data into options. """ if not self.project: self.tabWidget.addTab(self.canvas, "Default Project") return file = QtCore.QFile(self.project) if not file.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning(self, self.tr("Load Error"), self.tr("Cannot read file %1:\n%2.") .arg(self.project) .arg(file.errorString())) self.tabWidget.addTab(self.canvas, "Default Project") return _in = QtCore.QTextStream(file) QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) while not _in.atEnd(): line = str(_in.readLine()) option, value = line.split("=", 1) options[option] = value self.configWindow.updateSettings() QtGui.QApplication.restoreOverrideCursor() projectname = self.project.split("/")[-1].strip(".gproj") self.tabWidget.addTab(self.canvas, projectname) def closeProject(self): """ Close the current project. """ if self.running: self.log.append("You cannot close a project when it is still running!") return if isinstance(mainWidgets["canvas"], Tutorial): self.log.append("You cannot close a project during the tutorial!") return if self.tabWidget.count() == 1: self.tabWidget.addTab(self.canvas, "Default Project") self.project = "" else: self.tabWidget.removeTab(0) def export(self): """ Open an export window to generate an image from the canvas. """ self.exportWindow.show() def startBackend(self): """ Start the backend server. """ self.startServer() #self.startClient() def setRecovery(self, recovery): """ Set the recovering state of the topology. """ self.recovery = recovery def isRunning(self): """ Returns whether a topology is running or not. """ return self.running def startServer(self): """ Start the server backend of gbuilder, which controls running topologies. """ if self.server and self.server.poll() == None: self.log.append("A server is already running!") return base = "ssh -t " if options["username"] : base += options['username'] + "@" base += options["server"] tunnel = " -L " + options["localPort"] + ":localhost:" + options["remotePort"] server = "bash -c -i 'gserver " + options["remotePort"] + "' || sleep 5" command = "" if environ["os"] == "Windows": startpath = environ["tmp"] + "gserver.start" try: startFile = open(startpath, "w") startFile.write("echo -ne \"\\033]0;gserver\\007\"\n") startFile.write(server) startFile.close() except: self.log.append("Failed to write to start file!") return command += "putty -" if options["session"]: command += "load " + options["session"] + " -l " + options["username"] + " -t" else: command += base command += tunnel + " -m \"" + startpath + "\"" else: command += "xterm -T gserver -e " + base + tunnel + " \" " + server + "\"" self.server = subprocess.Popen(str(command), shell=True) def startClient(self): """ Start the client of gbuilder, which communicates with the server. """ self.client = Client(self) self.client.connectTo("localhost", int(options["localPort"]), 10) #self.client.start() mainWidgets["client"] = self.client def compile(self): """ Compile the current topology. """ if self.running: self.log.append("You cannot compile a topology when one is still running!") return False if self.saveTopology() == False: return False scene = self.canvas.scene() compiler = Compiler(scene.items(), self.filename) xmlFile = compiler.compile() self.properties.display() self.interfaces.display() self.routes.display() if xmlFile: self.statusBar().showMessage(self.tr("Compiled '%1'").arg(xmlFile), 2000) return True else: self.statusBar().showMessage(self.tr("Compile failed"), 2000) return False def run(self): """ Run the current topology. """ if not self.server or self.server.poll() != None: self.log.append("Please start the server first!") return if not self.client or not self.client.isConnected(): self.startClient() if self.isRunning() and not self.recovery: self.log.append("A topology is already running, please stop it first!") return scene = self.canvas.scene() items = scene.items() if items: if self.recovery: self.recovery = False elif options["autocompile"] and not self.compile(): return else: self.log.append("Please create or load a topology first!") return options["elasticMode"] = False xmlFile = self.filename.replace(".gsav", ".xml") if not os.access(xmlFile, os.F_OK): self.log.append("Please compile the topology first!") return self.tm.show() #self.progressBar.setValue(0) self.client.process("file . " + xmlFile) self.client.send("init " + self.project.split("/")[-1].strip(".gproj")) self.client.send("canvas %d,%d" % (scene.width(), scene.height())) for item in items: if item.type == "Mobile" or item.type == "Wireless_access_point": x = item.pos().x() y = item.pos().y() self.client.send("mobile %s %d,%d" % (item.getName(), x, y)) self.client.process("start " + xmlFile) self.running = True self.canvas.setAcceptDrops(False) scene = self.canvas.scene() scene.startRefresh() scene.clearSelection() self.properties.clear() self.interfaces.clear() self.routes.clear() def stop(self): """ Stop the current running topology. """ if not self.server or self.server.poll() != None: self.log.append("Please start the server first!") return if not self.client or not self.client.isConnected(): self.startClient() if self.recovery: self.recovery = False scene = self.canvas.scene() activeDevices = False from Core.Device import Device for item in scene.items(): if not isinstance(item, Device): continue if item.type == "Router": item.stop() if item.status: activeDevices = True if not activeDevices: self.stopped() elif not scene.isRefreshing(): scene.startRefresh() self.client.process("stop") def stopped(self): """ Handle a fully stopped topology. """ self.running = False self.canvas.scene().stopRefresh() self.tm.hide() self.canvas.setAcceptDrops(True) olddir = os.getcwd() os.chdir(environ["tmp"]) for tmpfile in os.listdir("."): if tmpfile.startswith("."): continue try: os.remove(tmpfile) except: continue os.chdir(olddir) def loadFile(self, filetype): """ Load a file through a file dialog. """ # Qt is very picky in the filename structure but python is not, so we use python # to form the correct path which will work for both Windows and Linux olddir = os.getcwd() os.chdir(environ["sav"]) loadpath = os.getcwd() os.chdir(olddir) filename = QtGui.QFileDialog.getOpenFileName(self, self.tr("Choose a file name"), loadpath, self.tr(filetype)) return filename def loadTopology(self): """ Load a topology. """ if self.running: self.log.append("You cannot load a topology when one is still running!") return if isinstance(mainWidgets["canvas"], Tutorial): self.log.append("You cannot load a topology during the tutorial!") return def loadIntoScene(line): scene = self.canvas.scene() itemType,arg = line.split(":") args = str(arg).strip("()").split(",") if itemType == "edge": source = scene.findItem(args[0]) dest = scene.findItem(args[1]) if source.type == "Mobile" or dest.type == "Mobile": item = Wireless_Connection(source, dest) else: item = Connection(source, dest) scene.addItem(item) else: devType, index = str(itemType).rsplit("_", 1) item = deviceTypes[devType]() item.setIndex(int(index)) scene.addItem(item) item.setPos(float(args[0]), float(args[1])) item.nudge() return item def loadProperties(itemDict): currentInterfaceTarget = None currentRouteSubnet = None for item, properties in itemDict.iteritems(): for line in properties: count = 0 while line.find("\t") == 0: line = line[1:] count += 1 prop, value = line.split(":", 1) if count == 1: item.setProperty(prop, value) elif count == 2: currentInterfaceTarget = self.canvas.scene().findItem(value) elif count == 3: item.setInterfaceProperty(prop, value, currentInterfaceTarget) elif count == 4: currentRouteSubnet = value item.addEntry("", "", value, currentInterfaceTarget) elif count == 5: item.setEntryProperty(prop, value, currentRouteSubnet, currentInterfaceTarget) filename = self.loadFile("GSAV (*.gsav)") if filename.isEmpty(): return file = QtCore.QFile(filename) if not file.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning(self, self.tr("Load Error"), self.tr("Cannot read file %1:\n%2.") .arg(filename) .arg(file.errorString())) return self.newScene() self.filename = str(filename) _in = QtCore.QTextStream(file) QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) itemDict = {} line = str(_in.readLine()) lines = [] while not _in.atEnd(): item = loadIntoScene(line) line = str(_in.readLine()) while line.find("\t") == 0: lines.append(line) line = str(_in.readLine()) itemDict[item] = lines lines = [] loadProperties(itemDict) QtGui.QApplication.restoreOverrideCursor() self.statusBar().showMessage(self.tr("Loaded '%1'").arg(filename), 2000) def saveFile(self, filetype): """ Save a file through a file dialog. """ olddir = os.getcwd() os.chdir(environ["sav"]) savepath = os.getcwd() os.chdir(olddir) filename = QtGui.QFileDialog.getSaveFileName(self, self.tr("Choose a file name"), savepath, self.tr(filetype.upper() + " (*.%s)" % filetype)) if filename.isEmpty(): return filename if not filename.toLower().endsWith("." + filetype): filename += "." + filetype return filename def saveTopologyAs(self): """ Save a topology under a given filename. """ if not self.canvas.scene().items(): self.log.append("There is nothing to save!") return False filename = self.saveFile("gsav") if filename.isEmpty(): return False self.filename = str(filename) return self.saveTopology() def saveTopology(self): """ Save a topology. """ if not self.canvas.scene().items(): self.log.append("There is nothing to save!") return False # for first time use if not self.filename: return self.saveTopologyAs() file = QtCore.QFile(self.filename) if not file.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning(self, self.tr("Save Error"), self.tr("Cannot write file %1:\n%2.") .arg(self.filename) .arg(file.errorString())) return False out = QtCore.QTextStream(file) QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) scene = self.canvas.scene() outstring = "" for item in scene.items(): if isinstance(item, Node): outstring += item.toString() for item in scene.items(): if isinstance(item, Edge): outstring += item.toString() out << outstring QtGui.QApplication.restoreOverrideCursor() self.statusBar().showMessage(self.tr("Saved '%1'").arg(self.filename), 2000) return True def copy(self): """ Copy selected text from the log into the paste buffer. """ self.log.copy() def config(self): """ Open the options window. """ self.configWindow.show() def arrange(self): """ Rearrange the topology based on the distance between nodes. """ if self.isRunning(): self.log.append("Cannot arrange while running!") return if isinstance(mainWidgets["canvas"], Tutorial): mainWidgets["log"].append("Cannot arrange during the tutorial!") return options["elasticMode"] = not options["elasticMode"] def about(self): """ Show the about window. """ QtGui.QMessageBox.about(self, self.tr("About %s %s" % (Core.globals.PROG_NAME, Core.globals.PROG_VERSION)), self.tr("<b>%s %s</b><br>Written by Daniel Ng<br>under the supervision of Muthucumaru Maheswaran" % (Core.globals.PROG_NAME, Core.globals.PROG_VERSION))) def createActions(self): """ Create the actions used in the menus and toolbars. """ self.newSceneAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "new.png"), self.tr("&New"), self) self.newSceneAct.setShortcut(self.tr("Ctrl+N")) self.newSceneAct.setStatusTip(self.tr("Create a new topology")) self.connect(self.newSceneAct, QtCore.SIGNAL("triggered()"), self.newScene) self.closeAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "close.png"), self.tr("&Close"), self) self.closeAct.setShortcut(self.tr("Ctrl+W")) self.closeAct.setStatusTip(self.tr("Close the current topology")) self.connect(self.closeAct, QtCore.SIGNAL("triggered()"), self.closeTopology) self.loadAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "open.png"), self.tr("&Open..."), self) self.loadAct.setShortcut(self.tr("Ctrl+O")) self.loadAct.setStatusTip(self.tr("Load a topology")) self.connect(self.loadAct, QtCore.SIGNAL("triggered()"), self.loadTopology) self.saveAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "save.png"), self.tr("&Save..."), self) self.saveAct.setShortcut(self.tr("Ctrl+S")) self.saveAct.setStatusTip(self.tr("Save the current topology")) self.connect(self.saveAct, QtCore.SIGNAL("triggered()"), self.saveTopology) self.saveAsAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "save.png"), self.tr("&Save As..."), self) self.saveAsAct.setShortcut(self.tr("Ctrl+Shift+S")) self.saveAsAct.setStatusTip(self.tr("Save the current topology under a given filename")) self.connect(self.saveAsAct, QtCore.SIGNAL("triggered()"), self.saveTopologyAs) self.sendFileAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "send.png"), self.tr("&Send File..."), self) self.sendFileAct.setShortcut(self.tr("Ctrl+F")) self.sendFileAct.setStatusTip(self.tr("Choose a file to send to the server")) self.connect(self.sendFileAct, QtCore.SIGNAL("triggered()"), self.sendFile) self.exportAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "export.png"), self.tr("&Export..."), self) self.exportAct.setShortcut(self.tr("Ctrl+P")) self.exportAct.setStatusTip(self.tr("Export the current topology as an image")) self.connect(self.exportAct, QtCore.SIGNAL("triggered()"), self.export) self.copyAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "copy.png"), self.tr("&Copy"), self) self.copyAct.setShortcut(self.tr("Ctrl+C")) self.copyAct.setStatusTip(self.tr("Copy the selected text")) self.connect(self.copyAct, QtCore.SIGNAL("triggered()"), self.copy) self.compileAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "compile.png"), self.tr("&Compile"), self) self.compileAct.setShortcut(self.tr("Ctrl+E")) self.compileAct.setStatusTip(self.tr("Compile the current topology")) self.connect(self.compileAct, QtCore.SIGNAL("triggered()"), self.compile) self.runAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "run.png"), self.tr("&Run"), self) self.runAct.setShortcut(self.tr("Ctrl+R")) self.runAct.setStatusTip(self.tr("Run the current topology")) self.connect(self.runAct, QtCore.SIGNAL("triggered()"), self.run) self.stopAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "stop.png"), self.tr("&Stop"), self) self.stopAct.setShortcut(self.tr("Ctrl+D")) self.stopAct.setStatusTip(self.tr("Stop the current topology")) self.connect(self.stopAct, QtCore.SIGNAL("triggered()"), self.stop) self.startServerAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "startServer.png"), self.tr("&Start Server"), self) self.startServerAct.setShortcut(self.tr("Ctrl+T")) self.startServerAct.setStatusTip(self.tr("Start the server")) self.connect(self.startServerAct, QtCore.SIGNAL("triggered()"), self.startBackend) self.optionsAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "options.png"), self.tr("&Options"), self) self.optionsAct.setShortcut(self.tr("F2")) self.optionsAct.setStatusTip(self.tr("Show the options window")) self.connect(self.optionsAct, QtCore.SIGNAL("triggered()"), self.config) self.arrangeAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "arrange.png"), self.tr("&Arrange"), self) self.arrangeAct.setShortcut(self.tr("Ctrl+A")) self.arrangeAct.setStatusTip(self.tr("Arranges the current topology")) self.connect(self.arrangeAct, QtCore.SIGNAL("triggered()"), self.arrange) self.resetLayoutAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "layout.png"), self.tr("Reset Layout"), self) self.resetLayoutAct.setStatusTip(self.tr("Reset dock windows to the saved layout")) self.connect(self.resetLayoutAct, QtCore.SIGNAL("triggered()"), self.resetLayout) self.expandSceneAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "expand.png"), self.tr("Expand Scene"), self) self.expandSceneAct.setStatusTip(self.tr("Expand the scene for more space")) self.connect(self.expandSceneAct, QtCore.SIGNAL("triggered()"), self.expandScene) self.quitAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "exit.png"), self.tr("&Quit"), self) self.quitAct.setShortcut(self.tr("Ctrl+Q")) self.quitAct.setStatusTip(self.tr("Quit the application")) self.connect(self.quitAct, QtCore.SIGNAL("triggered()"), self.quit) self.newProjectAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "new.png"), self.tr("&New"), self) self.newProjectAct.setShortcut(self.tr("Ctrl+Shift+N")) self.newProjectAct.setStatusTip(self.tr("Create a new project")) self.connect(self.newProjectAct, QtCore.SIGNAL("triggered()"), self.newProject) self.openProjectAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "open.png"), self.tr("&Open"), self) self.openProjectAct.setShortcut(self.tr("Ctrl+Shift+O")) self.openProjectAct.setStatusTip(self.tr("Open an existing project")) self.connect(self.openProjectAct, QtCore.SIGNAL("triggered()"), self.openProject) self.closeProjectAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "close.png"), self.tr("&Close"), self) self.closeProjectAct.setShortcut(self.tr("Ctrl+Shift+W")) self.closeProjectAct.setStatusTip(self.tr("Close the current project")) self.connect(self.closeProjectAct, QtCore.SIGNAL("triggered()"), self.closeProject) self.tutorialAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "tutorial.png"), self.tr("&Tutorial"), self) self.connect(self.tutorialAct, QtCore.SIGNAL("triggered()"), self.startTutorial) self.faqAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "help.png"), self.tr("&FAQ"), self) self.connect(self.faqAct, QtCore.SIGNAL("triggered()"), self.faq) self.aboutAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "giniLogo.png"), self.tr("&About"), self) self.aboutAct.setStatusTip(self.tr("Show the application's About box")) self.connect(self.aboutAct, QtCore.SIGNAL("triggered()"), self.about) self.aboutQtAct = QtGui.QAction(self.tr("About &Qt"), self) self.aboutQtAct.setStatusTip(self.tr("Show the Qt library's About box")) self.connect(self.aboutQtAct, QtCore.SIGNAL("triggered()"), QtGui.qApp, QtCore.SLOT("aboutQt()")) def createMenus(self): """ Create the menus with actions. """ self.fileMenu = self.menuBar().addMenu(self.tr("&File")) self.fileMenu.setPalette(defaultOptions["palette"]) self.fileMenu.addAction(self.newSceneAct) self.fileMenu.addAction(self.loadAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addAction(self.sendFileAct) self.fileMenu.addAction(self.exportAct) self.fileMenu.addAction(self.closeAct) self.fileMenu.addSeparator() self.fileMenu.addAction(self.quitAct) self.projectMenu = self.menuBar().addMenu(self.tr("&Project")) self.projectMenu.setPalette(defaultOptions["palette"]) self.projectMenu.addAction(self.newProjectAct) self.projectMenu.addAction(self.openProjectAct) self.projectMenu.addAction(self.closeProjectAct) self.editMenu = self.menuBar().addMenu(self.tr("&Edit")) self.editMenu.setPalette(defaultOptions["palette"]) self.editMenu.addAction(self.copyAct) self.editMenu.addAction(self.arrangeAct) self.editMenu.addAction(self.resetLayoutAct) self.editMenu.addAction(self.expandSceneAct) self.runMenu = self.menuBar().addMenu(self.tr("&Run")) self.runMenu.setPalette(defaultOptions["palette"]) self.runMenu.addAction(self.compileAct) self.runMenu.addAction(self.runAct) self.runMenu.addAction(self.stopAct) self.runMenu.addAction(self.startServerAct) self.configMenu = self.menuBar().addMenu(self.tr("&Config")) self.configMenu.setPalette(defaultOptions["palette"]) self.configMenu.addAction(self.optionsAct) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu(self.tr("&Help")) self.helpMenu.setPalette(defaultOptions["palette"]) self.helpMenu.addAction(self.tutorialAct) self.helpMenu.addAction(self.faqAct) self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutQtAct) def createPopupMenu(self): """ Customize the popup menu so that it is visible. """ popupMenu = QtGui.QMainWindow.createPopupMenu(self) popupMenu.setPalette(defaultOptions["palette"]) return popupMenu def createToolBars(self): """ Create the toolbars with actions. """ self.fileToolBar = self.addToolBar(self.tr("File")) self.fileToolBar.addAction(self.newSceneAct) self.fileToolBar.addAction(self.loadAct) self.fileToolBar.addAction(self.saveAct) self.fileToolBar.addAction(self.sendFileAct) self.fileToolBar.addAction(self.exportAct) self.fileToolBar.addAction(self.closeAct) self.editToolBar = self.addToolBar(self.tr("Edit")) self.editToolBar.addAction(self.copyAct) self.editToolBar.addAction(self.resetLayoutAct) self.editToolBar.addAction(self.expandSceneAct) self.runToolBar = self.addToolBar(self.tr("Run")) self.runToolBar.addAction(self.compileAct) self.runToolBar.addAction(self.runAct) self.runToolBar.addAction(self.stopAct) self.runToolBar.addAction(self.startServerAct) def createStatusBar(self): """ Create the status bar. """ self.statusBar().showMessage(self.tr("Ready")) def createProgressBar(self): """ Create the progress bar. """ self.progressBar = QtGui.QProgressBar() self.progressBar.setRange(0, 10000) self.progressBar.setValue(0) self.statusBar().addPermanentWidget(self.progressBar) self.progressBar.show() def getDeviceCount(self, alive=False): """ Return the interfaceable device count, or the alive ones if alive=True. """ from Core.Interfaceable import Interfaceable count = 0.0 for item in self.canvas.scene().items(): if isinstance(item, Interfaceable): if alive and item.status in ("", "dead"): continue count += 1.0 return count def updateProgressBar(self): """ Update the progress bar. """ maxVal = self.progressBar.maximum() finalVal = (self.getDeviceCount(True) / self.getDeviceCount()) * maxVal if finalVal < 0: finalVal = 0 self.progressBar.setValue(finalVal) if finalVal == 0: return True return False def createConfigWindows(self): """ Create the options window. """ self.configWindow = ConfigDialog(self) def createDockWindows(self): """ Create the dock windows: dropbar, log, properties, interfaces, routes. """ self.log = LogWindow(self.tr("Log"), self) self.log.append("Welcome to %s %s!\n" % (Core.globals.PROG_NAME, Core.globals.PROG_VERSION)) self.log.setGeometry(QtCore.QRect(0, 0, 800, 114)) mainWidgets["log"] = self.log self.dropbar = DropBar(self.tr("Components"), self) self.dropbar.setGeometry(QtCore.QRect(0, 0, 129, 390)) mainWidgets["drop"] = self.dropbar self.properties = PropertiesWindow(self) self.properties.setWindowTitle("Properties") mainWidgets["properties"] = self.properties self.interfaces = InterfacesWindow(self) self.interfaces.setWindowTitle("Interfaces") mainWidgets["interfaces"] = self.interfaces self.routes = RoutesWindow(self.interfaces, self) self.routes.setWindowTitle("Routes") mainWidgets["routes"] = self.routes self.tm = TaskManagerWindow(self) self.tm.setWindowTitle("Task Manager") mainWidgets["tm"] = self.tm self.debugWindow = QtGui.QDockWidget(self.tr("Debug Window")) self.debugWindow.setWidget(DebugWindow(self)) self.docks = {"Components":self.dropbar, "Log":self.log, "Properties":self.properties, "Interfaces":self.interfaces, "Routes":self.routes, "Task Manager":self.tm} self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dropbar) self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.log) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.properties) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.interfaces) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.routes) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.tm) self.tm.setFloating(True) self.routes.setFloating(True) self.debugWindow.setFloating(True) def createPopupWindows(self): """ Create the different popup windows. """ self.exportWindow = ExportWindow(self) self.sendWindow = SendDirectoryWindow(self) self.popup = QtGui.QMessageBox(self) self.popup.setIcon(QtGui.QMessageBox.Warning) self.popup.setWindowIcon(QtGui.QIcon(environ["images"]+"giniLogo.png")) mainWidgets["popup"] = self.popup def keyPressEvent(self, event): """ Handle specific shortcut keys. """ key = event.key() scene = self.canvas.scene() if key == QtCore.Qt.Key_Escape: scene.clearSelection() elif key == QtCore.Qt.Key_Delete: for item in scene.selectedItems(): item.delete() elif key == QtCore.Qt.Key_C: items = scene.items() if not items: return selected = scene.selectedItems() scene.clearSelection() if selected: index = items.index(selected[0]) items[index - 1].setSelected(True) else: items[0].setSelected(True) elif key == QtCore.Qt.Key_H: for dock in self.docks.values(): dock.setFloating(not dock.isFloating()) elif key == QtCore.Qt.Key_F10: self.debugWindow.show()
class MainWindow(Systray): def __init__(self, app): """ Create a main window for the given application. """ defaultOptions["palette"] = app.palette() Systray.__init__(self) self.expansions = 0 self.client = None self.server = None self.running = False self.recovery = False mainWidgets["main"] = self mainWidgets["app"] = app self.canvas = Canvas(self) mainWidgets["canvas"] = self.canvas self.tabWidget = TabWidget(self) mainWidgets["tab"] = self.tabWidget self.setCentralWidget(self.tabWidget) #self.setCentralWidget(self.canvas) self.createActions() self.createMenus() self.createToolBars() self.createStatusBar() self.createDockWindows() self.createConfigWindows() self.createPopupWindows() self.createProgressBar() self.newScene() self.debugWindow.hide() self.tm.hide() self.routes.hide() self.setVisible(True) self.center() self.saveLayout(environ["config"] + "defaultLayout") self.defaultLayout = True if options["restore"]: self.loadLayout() self.defaultLayout = False self.loadProject() atexit.register(self.cleanup) def center(self): """ Center the window. """ screen = QtGui.QDesktopWidget().screenGeometry() rect = self.geometry() self.move((screen.width() - rect.width()) / 2, (screen.height() - rect.height()) / 2) self.show() def getProject(self): """ Return the project. """ return self.project def startTutorial(self): """ Start the interactive tutorial. """ if isinstance(mainWidgets["canvas"], Tutorial): self.log.append( "You are already doing the tutorial! If you would like to stop or restart, select 'Close' from the File menu now." ) return if not self.closeTopology(): return self.project = "Tutorial" self.filename = "" self.canvas = Tutorial(self) mainWidgets["canvas"] = self.canvas self.tabWidget.removeTab(0) self.tabWidget.addTab(self.canvas, "Tutorial") self.canvas.start() for nodeType in nodeTypes.keys(): itemTypes = nodeTypes[nodeType] itemTypes[nodeType] = 0 self.properties.clear() self.interfaces.clear() self.routes.clear() self.resetLayout(True) self.lockDocks() def lockDocks(self): """ Lock the dock windows so they cannot be moved, closed or resized. """ self.tm.hide() for dock in self.docks.values(): dock.setFeatures(dock.NoDockWidgetFeatures) def unlockDocks(self): """ Unlock the dock windows. """ self.tm.show() for dock in self.docks.values(): dock.setFeatures(dock.DockWidgetClosable | dock.DockWidgetMovable | dock.DockWidgetFloatable) def faq(self): """ Open the FAQ in the default browser. """ olddir = os.getcwd() os.chdir(environ["doc"]) loadpath = os.getcwd() os.chdir(olddir) if environ["os"] == "Windows": url = QtCore.QUrl("file:///" + loadpath + "/FAQ.html") else: url = QtCore.QUrl("file://" + loadpath + "/FAQ.html") QtGui.QDesktopServices.openUrl(url) def closeTopology(self): """ Close the current topology. """ if self.running: self.log.append( "You cannot close a topology when one is still running!") return False scene = self.canvas.scene() if scene and scene.items(): reply = QtGui.QMessageBox.warning( self, self.tr(Core.globals.PROG_NAME), self.tr("Save before closing?"), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No | QtGui.QMessageBox.Cancel) if reply == QtGui.QMessageBox.Yes: if not self.saveTopology(): return False elif reply == QtGui.QMessageBox.No: pass else: return False if isinstance(mainWidgets["canvas"], Tutorial): self.canvas = Canvas(self) mainWidgets["canvas"] = self.canvas self.tabWidget.removeTab(0) self.tabWidget.addTab(self.canvas, "Default Project") self.project = "" self.unlockDocks() self.filename = "" scene = Scene(self.canvas) scene.setItemIndexMethod(QtGui.QGraphicsScene.NoIndex) self.canvas.setScene(scene) self.expansions = 0 for nodeType in nodeTypes.keys(): itemTypes = nodeTypes[nodeType] itemTypes[nodeType] = 0 self.properties.clear() self.interfaces.clear() self.routes.clear() return True def sendFile(self): """ Start a process to select and send a file to the server. """ if not self.server or self.server.poll() != None: self.log.append("Please start the server first!") return if not self.client or not self.client.isConnected(): self.startClient() filename = self.loadFile("All Files (*.*)") if not filename: return self.sendWindow.setFilename(filename) self.sendWindow.show() def newScene(self): """ Close the current topology and create a new one. """ if self.running: self.log.append( "You cannot create a new topology when one is still running!") return if isinstance(mainWidgets["canvas"], Tutorial): self.log.append( "You cannot create a new topology during the tutorial!") return if not self.closeTopology(): return self.expandScene() def expandScene(self): """ Expand the scene based on number of expansions. """ x = 175 + self.expansions * 30 y = 160 + self.expansions * 20 scene = self.canvas.scene() item = QtGui.QGraphicsLineItem(-x, -y, x, y) scene.addItem(item) scene.removeItem(item) self.expansions += 1 def newProject(self): """ Create a new project for device sharing. """ if self.running: self.log.append( "You cannot create a new project when one is still running!") return if isinstance(mainWidgets["canvas"], Tutorial): self.log.append( "You cannot create a new project during the tutorial!") return filename = self.saveFile("gproj") if filename.isEmpty(): return projectname = str(filename).split("/")[-1].strip(".gproj") from Core.Item import nodeTypes for nodeType in nodeTypes: if projectname.startswith(nodeType + "_"): self.popup.setWindowTitle("Invalid Project Name") self.popup.setText( "You cannot name a project starting with the name of a device and underscore!" ) self.popup.show() return self.project = str(filename) file = QtCore.QFile(filename) if not file.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning( self, self.tr("Save Error"), self.tr("Cannot write file %1:\n%2.").arg(self.filename).arg( file.errorString())) return out = QtCore.QTextStream(file) QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) if options["username"]: out << "username="******"username"] + "\n" else: self.log.append("Warning, no username is specified!") if options["session"]: out << "session=" + options["session"] + "\n" elif options["server"]: out << "server=" + options["server"] + "\n" else: self.log.append("Warning, no server or session name is specified!") QtGui.QApplication.restoreOverrideCursor() self.tabWidget.addTab(self.canvas, projectname) def openProject(self): """ Load an existing project for device sharing. """ if self.running: self.log.append( "You cannot open a project when one is still running!") return if isinstance(mainWidgets["canvas"], Tutorial): self.log.append("You cannot open a project during the tutorial!") return filename = self.loadFile("GPROJ (*.gproj)") if filename.isEmpty(): return self.project = str(filename) self.loadProject() def loadProject(self): """ Load project file data into options. """ if not self.project: self.tabWidget.addTab(self.canvas, "Default Project") return file = QtCore.QFile(self.project) if not file.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning( self, self.tr("Load Error"), self.tr("Cannot read file %1:\n%2.").arg(self.project).arg( file.errorString())) self.tabWidget.addTab(self.canvas, "Default Project") return _in = QtCore.QTextStream(file) QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) while not _in.atEnd(): line = str(_in.readLine()) option, value = line.split("=", 1) options[option] = value self.configWindow.updateSettings() QtGui.QApplication.restoreOverrideCursor() projectname = self.project.split("/")[-1].strip(".gproj") self.tabWidget.addTab(self.canvas, projectname) def closeProject(self): """ Close the current project. """ if self.running: self.log.append( "You cannot close a project when it is still running!") return if isinstance(mainWidgets["canvas"], Tutorial): self.log.append("You cannot close a project during the tutorial!") return if self.tabWidget.count() == 1: self.tabWidget.addTab(self.canvas, "Default Project") self.project = "" else: self.tabWidget.removeTab(0) def export(self): """ Open an export window to generate an image from the canvas. """ self.exportWindow.show() def startBackend(self): """ Start the backend server. """ self.startServer() #self.startClient() def setRecovery(self, recovery): """ Set the recovering state of the topology. """ self.recovery = recovery def isRunning(self): """ Returns whether a topology is running or not. """ return self.running def startServer(self): """ Start the server backend of gbuilder, which controls running topologies. """ if self.server and self.server.poll() == None: self.log.append("A server is already running!") return base = "ssh -t " + options["username"] + "@" + options["server"] tunnel = " -L " + options["localPort"] + ":localhost:" + options[ "remotePort"] server = "bash -c -i 'gserver " + options["remotePort"] + "' || sleep 5" command = "" gserver = "gserver" if environ["os"] == "Windows": startpath = environ["tmp"] + "gserver.start" try: startFile = open(startpath, "w") startFile.write("echo -ne \"\\033]0;" + gserver + "\\007\"\n") startFile.write(server) startFile.close() except: self.log.append("Failed to write to start file!") return command += "putty -" if options["session"]: command += "load " + options["session"] + " -l " + options[ "username"] + " -t" else: command += base command += tunnel + " -m \"" + startpath + "\"" else: command += "rxvt -T \"" + gserver + "\" -e " + base + tunnel + " \" " + server + "\"" self.server = subprocess.Popen(str(command), shell=True, preexec_fn=os.setpgrp) def startClient(self): """ Start the client of gbuilder, which communicates with the server. """ self.client = Client(self) self.client.connectTo("localhost", int(options["localPort"]), 10) #self.client.start() mainWidgets["client"] = self.client def compile(self): """ Compile the current topology. """ if self.running: self.log.append( "You cannot compile a topology when one is still running!") return False if self.saveTopology() == False: return False scene = self.canvas.scene() compiler = Compiler(scene.items(), self.filename) xmlFile = compiler.compile() self.properties.display() self.interfaces.display() self.routes.display() if xmlFile: self.statusBar().showMessage( self.tr("Compiled '%1'").arg(xmlFile), 2000) return True else: self.statusBar().showMessage(self.tr("Compile failed"), 2000) return False def run(self): """ Run the current topology. """ if not self.server or self.server.poll() != None: self.log.append("Please start the server first!") return if not self.client or not self.client.isConnected(): self.startClient() if self.isRunning() and not self.recovery: self.log.append( "A topology is already running, please stop it first!") return scene = self.canvas.scene() items = scene.items() if items: if self.recovery: self.recovery = False elif options["autocompile"] and not self.compile(): return else: self.log.append("Please create or load a topology first!") return options["elasticMode"] = False xmlFile = self.filename.replace(".gsav", ".xml") if not os.access(xmlFile, os.F_OK): self.log.append("Please compile the topology first!") return self.tm.show() #self.progressBar.setValue(0) self.client.process("file . " + xmlFile) self.client.send("init " + self.project.split("/")[-1].strip(".gproj")) self.client.send("canvas %d,%d" % (scene.width(), scene.height())) for item in items: if item.device_type == "Mobile" or item.device_type == "Wireless_access_point": x = item.pos().x() y = item.pos().y() self.client.send("mobile %s %d,%d" % (item.getName(), x, y)) self.client.process("start " + xmlFile) self.running = True self.canvas.setAcceptDrops(False) scene = self.canvas.scene() scene.startRefresh() scene.clearSelection() self.properties.clear() self.interfaces.clear() self.routes.clear() def stop(self): """ Stop the current running topology. """ if not self.server or self.server.poll() != None: self.log.append("Please start the server first!") return if not self.client or not self.client.isConnected(): self.startClient() if self.recovery: self.recovery = False scene = self.canvas.scene() activeDevices = False from Core.Device import Device for item in scene.items(): if not isinstance(item, Device): continue if item.device_type == "Router": item.stop() if item.status: activeDevices = True if not activeDevices: self.stopped() elif not scene.isRefreshing(): scene.startRefresh() self.client.process("stop") def stopped(self): """ Handle a fully stopped topology. """ self.running = False self.canvas.scene().stopRefresh() self.tm.hide() self.canvas.setAcceptDrops(True) olddir = os.getcwd() os.chdir(environ["tmp"]) for tmpfile in os.listdir("."): if tmpfile.startswith("."): continue try: os.remove(tmpfile) except: continue os.chdir(olddir) def loadFile(self, filetype): """ Load a file through a file dialog. """ # Qt is very picky in the filename structure but python is not, so we use python # to form the correct path which will work for both Windows and Linux olddir = os.getcwd() os.chdir(environ["sav"]) loadpath = os.getcwd() os.chdir(olddir) filename = QtGui.QFileDialog.getOpenFileName( self, self.tr("Choose a file name"), loadpath, self.tr(filetype)) return filename def loadTopology(self): """ Load a topology. """ if self.running: self.log.append( "You cannot load a topology when one is still running!") return if isinstance(mainWidgets["canvas"], Tutorial): self.log.append("You cannot load a topology during the tutorial!") return def loadIntoScene(line): scene = self.canvas.scene() itemType, arg = line.split(":") args = str(arg).strip("()").split(",") if itemType == "edge": source = scene.findItem(args[0]) dest = scene.findItem(args[1]) if source.device_type == "Mobile" or dest.device_type == "Mobile": item = Wireless_Connection(source, dest) else: item = Connection(source, dest) scene.addItem(item) else: devType, index = str(itemType).rsplit("_", 1) item = deviceTypes[devType]() item.setIndex(int(index)) scene.addItem(item) item.setPos(float(args[0]), float(args[1])) item.nudge() return item def loadProperties(itemDict): currentInterfaceTarget = None currentRouteSubnet = None for item, properties in itemDict.iteritems(): for line in properties: count = 0 while line.find("\t") == 0: line = line[1:] count += 1 prop, value = line.split(":", 1) if count == 1: item.setProperty(prop, value) elif count == 2: currentInterfaceTarget = self.canvas.scene().findItem( value) elif count == 3: item.setInterfaceProperty(prop, value, currentInterfaceTarget) elif count == 4: currentRouteSubnet = value item.addEntry("", "", value, currentInterfaceTarget) elif count == 5: item.setEntryProperty(prop, value, currentRouteSubnet, currentInterfaceTarget) filename = self.loadFile("GSAV (*.gsav)") if filename.isEmpty(): return file = QtCore.QFile(filename) if not file.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning( self, self.tr("Load Error"), self.tr("Cannot read file %1:\n%2.").arg(filename).arg( file.errorString())) return self.newScene() self.filename = str(filename) _in = QtCore.QTextStream(file) QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) itemDict = {} line = str(_in.readLine()) lines = [] while not _in.atEnd(): item = loadIntoScene(line) line = str(_in.readLine()) while line.find("\t") == 0: lines.append(line) line = str(_in.readLine()) itemDict[item] = lines lines = [] loadProperties(itemDict) QtGui.QApplication.restoreOverrideCursor() self.statusBar().showMessage( self.tr("Loaded '%1'").arg(filename), 2000) def saveFile(self, filetype): """ Save a file through a file dialog. """ olddir = os.getcwd() os.chdir(environ["sav"]) savepath = os.getcwd() os.chdir(olddir) filename = QtGui.QFileDialog.getSaveFileName( self, self.tr("Choose a file name"), savepath, self.tr(filetype.upper() + " (*.%s)" % filetype)) if filename.isEmpty(): return filename if not filename.toLower().endsWith("." + filetype): filename += "." + filetype return filename def saveTopologyAs(self): """ Save a topology under a given filename. """ if not self.canvas.scene().items(): self.log.append("There is nothing to save!") return False filename = self.saveFile("gsav") if filename.isEmpty(): return False self.filename = str(filename) return self.saveTopology() def saveTopology(self): """ Save a topology. """ if not self.canvas.scene().items(): self.log.append("There is nothing to save!") return False # for first time use if not self.filename: return self.saveTopologyAs() file = QtCore.QFile(self.filename) if not file.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning( self, self.tr("Save Error"), self.tr("Cannot write file %1:\n%2.").arg(self.filename).arg( file.errorString())) return False out = QtCore.QTextStream(file) QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) scene = self.canvas.scene() outstring = "" for item in scene.items(): if isinstance(item, Node): outstring += item.toString() for item in scene.items(): if isinstance(item, Edge): outstring += item.toString() out << outstring QtGui.QApplication.restoreOverrideCursor() self.statusBar().showMessage( self.tr("Saved '%1'").arg(self.filename), 2000) return True def copy(self): """ Copy selected text from the log into the paste buffer. """ self.log.copy() def config(self): """ Open the options window. """ self.configWindow.show() def arrange(self): """ Rearrange the topology based on the distance between nodes. """ if self.isRunning(): self.log.append("Cannot arrange while running!") return if isinstance(mainWidgets["canvas"], Tutorial): mainWidgets["log"].append("Cannot arrange during the tutorial!") return options["elasticMode"] = not options["elasticMode"] def about(self): """ Show the about window. """ QtGui.QMessageBox.about( self, self.tr("About %s %s" % (Core.globals.PROG_NAME, Core.globals.PROG_VERSION)), self. tr("<b>%s %s</b><br>Written by Daniel Ng<br>under the supervision of Muthucumaru Maheswaran" % (Core.globals.PROG_NAME, Core.globals.PROG_VERSION))) def createActions(self): """ Create the actions used in the menus and toolbars. """ self.newSceneAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "new.png"), self.tr("&New"), self) self.newSceneAct.setShortcut(self.tr("Ctrl+N")) self.newSceneAct.setStatusTip(self.tr("Create a new topology")) self.connect(self.newSceneAct, QtCore.SIGNAL("triggered()"), self.newScene) self.closeAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "close.png"), self.tr("&Close"), self) self.closeAct.setShortcut(self.tr("Ctrl+W")) self.closeAct.setStatusTip(self.tr("Close the current topology")) self.connect(self.closeAct, QtCore.SIGNAL("triggered()"), self.closeTopology) self.loadAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "open.png"), self.tr("&Open..."), self) self.loadAct.setShortcut(self.tr("Ctrl+O")) self.loadAct.setStatusTip(self.tr("Load a topology")) self.connect(self.loadAct, QtCore.SIGNAL("triggered()"), self.loadTopology) self.saveAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "save.png"), self.tr("&Save..."), self) self.saveAct.setShortcut(self.tr("Ctrl+S")) self.saveAct.setStatusTip(self.tr("Save the current topology")) self.connect(self.saveAct, QtCore.SIGNAL("triggered()"), self.saveTopology) self.saveAsAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "save.png"), self.tr("&Save As..."), self) self.saveAsAct.setShortcut(self.tr("Ctrl+Shift+S")) self.saveAsAct.setStatusTip( self.tr("Save the current topology under a given filename")) self.connect(self.saveAsAct, QtCore.SIGNAL("triggered()"), self.saveTopologyAs) self.sendFileAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "send.png"), self.tr("&Send File..."), self) self.sendFileAct.setShortcut(self.tr("Ctrl+F")) self.sendFileAct.setStatusTip( self.tr("Choose a file to send to the server")) self.connect(self.sendFileAct, QtCore.SIGNAL("triggered()"), self.sendFile) self.exportAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "export.png"), self.tr("&Export..."), self) self.exportAct.setShortcut(self.tr("Ctrl+P")) self.exportAct.setStatusTip( self.tr("Export the current topology as an image")) self.connect(self.exportAct, QtCore.SIGNAL("triggered()"), self.export) self.copyAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "copy.png"), self.tr("&Copy"), self) self.copyAct.setShortcut(self.tr("Ctrl+C")) self.copyAct.setStatusTip(self.tr("Copy the selected text")) self.connect(self.copyAct, QtCore.SIGNAL("triggered()"), self.copy) self.compileAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "compile.png"), self.tr("&Compile"), self) self.compileAct.setShortcut(self.tr("Ctrl+E")) self.compileAct.setStatusTip(self.tr("Compile the current topology")) self.connect(self.compileAct, QtCore.SIGNAL("triggered()"), self.compile) self.runAct = QtGui.QAction(QtGui.QIcon(environ["images"] + "run.png"), self.tr("&Run"), self) self.runAct.setShortcut(self.tr("Ctrl+R")) self.runAct.setStatusTip(self.tr("Run the current topology")) self.connect(self.runAct, QtCore.SIGNAL("triggered()"), self.run) self.stopAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "stop.png"), self.tr("&Stop"), self) self.stopAct.setShortcut(self.tr("Ctrl+D")) self.stopAct.setStatusTip(self.tr("Stop the current topology")) self.connect(self.stopAct, QtCore.SIGNAL("triggered()"), self.stop) self.startServerAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "startServer.png"), self.tr("&Start Server"), self) self.startServerAct.setShortcut(self.tr("Ctrl+T")) self.startServerAct.setStatusTip(self.tr("Start the server")) self.connect(self.startServerAct, QtCore.SIGNAL("triggered()"), self.startBackend) self.optionsAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "options.png"), self.tr("&Options"), self) self.optionsAct.setShortcut(self.tr("F2")) self.optionsAct.setStatusTip(self.tr("Show the options window")) self.connect(self.optionsAct, QtCore.SIGNAL("triggered()"), self.config) self.arrangeAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "arrange.png"), self.tr("&Arrange"), self) self.arrangeAct.setShortcut(self.tr("Ctrl+A")) self.arrangeAct.setStatusTip(self.tr("Arranges the current topology")) self.connect(self.arrangeAct, QtCore.SIGNAL("triggered()"), self.arrange) self.resetLayoutAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "layout.png"), self.tr("Reset Layout"), self) self.resetLayoutAct.setStatusTip( self.tr("Reset dock windows to the saved layout")) self.connect(self.resetLayoutAct, QtCore.SIGNAL("triggered()"), self.resetLayout) self.expandSceneAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "expand.png"), self.tr("Expand Scene"), self) self.expandSceneAct.setStatusTip( self.tr("Expand the scene for more space")) self.connect(self.expandSceneAct, QtCore.SIGNAL("triggered()"), self.expandScene) self.quitAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "exit.png"), self.tr("&Quit"), self) self.quitAct.setShortcut(self.tr("Ctrl+Q")) self.quitAct.setStatusTip(self.tr("Quit the application")) self.connect(self.quitAct, QtCore.SIGNAL("triggered()"), self.quit) self.newProjectAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "new.png"), self.tr("&New"), self) self.newProjectAct.setShortcut(self.tr("Ctrl+Shift+N")) self.newProjectAct.setStatusTip(self.tr("Create a new project")) self.connect(self.newProjectAct, QtCore.SIGNAL("triggered()"), self.newProject) self.openProjectAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "open.png"), self.tr("&Open"), self) self.openProjectAct.setShortcut(self.tr("Ctrl+Shift+O")) self.openProjectAct.setStatusTip(self.tr("Open an existing project")) self.connect(self.openProjectAct, QtCore.SIGNAL("triggered()"), self.openProject) self.closeProjectAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "close.png"), self.tr("&Close"), self) self.closeProjectAct.setShortcut(self.tr("Ctrl+Shift+W")) self.closeProjectAct.setStatusTip(self.tr("Close the current project")) self.connect(self.closeProjectAct, QtCore.SIGNAL("triggered()"), self.closeProject) self.tutorialAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "tutorial.png"), self.tr("&Tutorial"), self) self.connect(self.tutorialAct, QtCore.SIGNAL("triggered()"), self.startTutorial) self.faqAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "help.png"), self.tr("&FAQ"), self) self.connect(self.faqAct, QtCore.SIGNAL("triggered()"), self.faq) self.aboutAct = QtGui.QAction( QtGui.QIcon(environ["images"] + "giniLogo.png"), self.tr("&About"), self) self.aboutAct.setStatusTip(self.tr("Show the application's About box")) self.connect(self.aboutAct, QtCore.SIGNAL("triggered()"), self.about) self.aboutQtAct = QtGui.QAction(self.tr("About &Qt"), self) self.aboutQtAct.setStatusTip( self.tr("Show the Qt library's About box")) self.connect(self.aboutQtAct, QtCore.SIGNAL("triggered()"), QtGui.qApp, QtCore.SLOT("aboutQt()")) def createMenus(self): """ Create the menus with actions. """ self.fileMenu = self.menuBar().addMenu(self.tr("&File")) self.fileMenu.setPalette(defaultOptions["palette"]) self.fileMenu.addAction(self.newSceneAct) self.fileMenu.addAction(self.loadAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addAction(self.sendFileAct) self.fileMenu.addAction(self.exportAct) self.fileMenu.addAction(self.closeAct) self.fileMenu.addSeparator() self.fileMenu.addAction(self.quitAct) self.projectMenu = self.menuBar().addMenu(self.tr("&Project")) self.projectMenu.setPalette(defaultOptions["palette"]) self.projectMenu.addAction(self.newProjectAct) self.projectMenu.addAction(self.openProjectAct) self.projectMenu.addAction(self.closeProjectAct) self.editMenu = self.menuBar().addMenu(self.tr("&Edit")) self.editMenu.setPalette(defaultOptions["palette"]) self.editMenu.addAction(self.copyAct) self.editMenu.addAction(self.arrangeAct) self.editMenu.addAction(self.resetLayoutAct) self.editMenu.addAction(self.expandSceneAct) self.runMenu = self.menuBar().addMenu(self.tr("&Run")) self.runMenu.setPalette(defaultOptions["palette"]) self.runMenu.addAction(self.compileAct) self.runMenu.addAction(self.runAct) self.runMenu.addAction(self.stopAct) self.runMenu.addAction(self.startServerAct) self.configMenu = self.menuBar().addMenu(self.tr("&Config")) self.configMenu.setPalette(defaultOptions["palette"]) self.configMenu.addAction(self.optionsAct) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu(self.tr("&Help")) self.helpMenu.setPalette(defaultOptions["palette"]) self.helpMenu.addAction(self.tutorialAct) self.helpMenu.addAction(self.faqAct) self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutQtAct) def createPopupMenu(self): """ Customize the popup menu so that it is visible. """ popupMenu = QtGui.QMainWindow.createPopupMenu(self) popupMenu.setPalette(defaultOptions["palette"]) return popupMenu def createToolBars(self): """ Create the toolbars with actions. """ self.fileToolBar = self.addToolBar(self.tr("File")) self.fileToolBar.addAction(self.newSceneAct) self.fileToolBar.addAction(self.loadAct) self.fileToolBar.addAction(self.saveAct) self.fileToolBar.addAction(self.sendFileAct) self.fileToolBar.addAction(self.exportAct) self.fileToolBar.addAction(self.closeAct) self.editToolBar = self.addToolBar(self.tr("Edit")) self.editToolBar.addAction(self.copyAct) self.editToolBar.addAction(self.resetLayoutAct) self.editToolBar.addAction(self.expandSceneAct) self.runToolBar = self.addToolBar(self.tr("Run")) self.runToolBar.addAction(self.compileAct) self.runToolBar.addAction(self.runAct) self.runToolBar.addAction(self.stopAct) self.runToolBar.addAction(self.startServerAct) def createStatusBar(self): """ Create the status bar. """ self.statusBar().showMessage(self.tr("Ready")) def createProgressBar(self): """ Create the progress bar. """ self.progressBar = QtGui.QProgressBar() self.progressBar.setRange(0, 10000) self.progressBar.setValue(0) self.statusBar().addPermanentWidget(self.progressBar) self.progressBar.show() def getDeviceCount(self, alive=False): """ Return the interfaceable device count, or the alive ones if alive=True. """ from Core.Interfaceable import Interfaceable count = 0.0 for item in self.canvas.scene().items(): if isinstance(item, Interfaceable): if item.device_type != "REALM": if alive and item.status in ("", "dead"): continue count += 1.0 return count def updateProgressBar(self): """ Update the progress bar. """ maxVal = self.progressBar.maximum() finalVal = (self.getDeviceCount(True) / self.getDeviceCount()) * maxVal if finalVal < 0: finalVal = 0 self.progressBar.setValue(finalVal) if finalVal == 0: return True return False def createConfigWindows(self): """ Create the options window. """ self.configWindow = ConfigDialog(self) def createDockWindows(self): """ Create the dock windows: dropbar, log, properties, interfaces, routes. """ self.log = LogWindow(self.tr("Log"), self) self.log.append("Welcome to %s %s!\n" % (Core.globals.PROG_NAME, Core.globals.PROG_VERSION)) self.log.setGeometry(QtCore.QRect(0, 0, 800, 114)) mainWidgets["log"] = self.log self.dropbar = DropBar(self.tr("Components"), self) self.dropbar.setGeometry(QtCore.QRect(0, 0, 129, 390)) mainWidgets["drop"] = self.dropbar self.properties = PropertiesWindow(self) self.properties.setWindowTitle("Properties") mainWidgets["properties"] = self.properties self.interfaces = InterfacesWindow(self) self.interfaces.setWindowTitle("Interfaces") mainWidgets["interfaces"] = self.interfaces self.routes = RoutesWindow(self.interfaces, self) self.routes.setWindowTitle("Routes") mainWidgets["routes"] = self.routes self.tm = TaskManagerWindow(self) self.tm.setWindowTitle("Task Manager") mainWidgets["tm"] = self.tm self.debugWindow = QtGui.QDockWidget(self.tr("Debug Window")) self.debugWindow.setWidget(DebugWindow(self)) self.docks = { "Components": self.dropbar, "Log": self.log, "Properties": self.properties, "Interfaces": self.interfaces, "Routes": self.routes, "Task Manager": self.tm } self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dropbar) self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.log) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.properties) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.interfaces) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.routes) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.tm) self.tm.setFloating(True) self.routes.setFloating(True) self.debugWindow.setFloating(True) def createPopupWindows(self): """ Create the different popup windows. """ self.exportWindow = ExportWindow(self) self.sendWindow = SendDirectoryWindow(self) self.popup = QtGui.QMessageBox(self) self.popup.setIcon(QtGui.QMessageBox.Warning) self.popup.setWindowIcon( QtGui.QIcon(environ["images"] + "giniLogo.png")) mainWidgets["popup"] = self.popup def keyPressEvent(self, event): """ Handle specific shortcut keys. """ key = event.key() scene = self.canvas.scene() if key == QtCore.Qt.Key_Escape: scene.clearSelection() elif key == QtCore.Qt.Key_Delete: for item in scene.selectedItems(): item.delete() elif key == QtCore.Qt.Key_C: items = scene.items() if not items: return selected = scene.selectedItems() scene.clearSelection() if selected: index = items.index(selected[0]) items[index - 1].setSelected(True) else: items[0].setSelected(True) elif key == QtCore.Qt.Key_H: for dock in self.docks.values(): dock.setFloating(not dock.isFloating()) elif key == QtCore.Qt.Key_F10: self.debugWindow.show() def cleanup(self): if self.server != None: self.server.kill()
class DashboardPage(QWidget): def __init__(self, parent=None): super(DashboardPage, self).__init__(parent) self.parent = parent self.menuBar = MenuBar(self) path = self.parent.path self.createBtn = QPushButton('Create') self.menuBar.setFirstChaOfUsername("candy") self.menuBar.move(QPoint(0, 0)) self.tabBarBoard = TabWidget() self.tabBarBoard.setFixedSize(585, 355) self.tabBarBoard.setFont(QFont("Moon", 10, QFont.Bold)) self.displayBoard = DisplayBoardBox() self.addBoardBtn = QPushButton("Add") self.addBoardBtn.setIcon(QIcon(path + "\\add.png")) self.addBoardBtn.setStyleSheet( "background-color:rgb(14,172,120);color:rgb(255,255,255)") self.addBoardBtn.setFont(QFont("Century Gothic", 8, QFont.Bold)) self.addBoardBtn.clicked.connect(self.createNewBoard) self.deleteBoardBtn = QPushButton("Delete") self.deleteBoardBtn.setIcon(QIcon(path + "\\delete.png")) self.deleteBoardBtn.setStyleSheet( "background-color:rgb(210,39,62);color:rgb(255,255,255)") self.deleteBoardBtn.setFont(QFont("Century Gothic", 8, QFont.Bold)) self.tabBarBoard.addTab(self.displayBoard, QIcon( path + "\\dashboard.png"), " Board") self.layout = QGridLayout() self.menuBar.setContentsMargins(0, 0, 0, 0) self.layout.addWidget(self.menuBar, 0, 0) self.tabBarBoard.setContentsMargins(14, 0, 30, 0) self.layout.addWidget(self.tabBarBoard, 1, 0, 1, 2) self.btnLayout = QHBoxLayout() self.btnLayout.addStretch(1) self.btnLayout.addWidget(self.addBoardBtn) self.btnLayout.addWidget(self.deleteBoardBtn) self.layout.addLayout(self.btnLayout, 2, 0) self.setLayout(self.layout) self.show() def createNewBoard(self): self.createBoardDialog = QDialog(self) self.createBoardDialog.setWindowTitle("Create board") self.formLayout = QFormLayout() self.boardTitleLabel = QLabel("Board Name: ") self.boardTitleValue = QLineEdit(self) self.formLayout.addRow(self.boardTitleLabel, self.boardTitleValue) self.formLayout.addRow(self.createBtn) self.createBoardDialog.setLayout(self.formLayout) self.boardTitleLabel.setFont(QFont("Century Gothic", 10,QFont.Bold)) self.boardTitleLabel.setStyleSheet("color:rgb(49,68,111)") self.boardTitleValue.setFont(QFont("Century Gothic", 10)) self.createBtn.setFont(QFont("Moon", 10,QFont.Bold)) self.createBtn.setStyleSheet("background-color:rgb(250,231,110);color:rgb(49,68,111)") self.createBoardDialog.show() def getBoardTitle(self): return self.boardTitleValue.text() def addBoard(self, boardDict): self.displayBoard.createBox(boardDict) def deleteAllBoard(self): self.displayBoard.listWidget.clear() def validateBoardTitle(self): if self.boardTitleValue.text() == '': createErrorDialogBox(self,"Error","Board title cannot be empty") return False return True def showBoardTitleIsExist(self): createErrorDialogBox(self,"Error","Board title is already exist") def closeDialog(self): self.createBoardDialog.reject() def deleteSelectBoard(self): self.selectBoard = self.displayBoard.listWidget.selectedItems() self.selectItemId = self.displayBoard.getSelectItemInBoardId() if not self.selectBoard: return for item in self.selectBoard: self.displayBoard.listWidget.takeItem( self.displayBoard.listWidget.row(item)) return self.selectItemId def deleteBoardId(self,boardId): for i in range(self.displayBoard.listWidget.count()): id = self.displayBoard.listWidget.item(i).getId() if(id == boardId): selectItem = self.displayBoard.listWidget.takeItem(i)