class ImagePlayer(QWidget): def __init__(self, filename, title, parent=None): QWidget.__init__(self, parent) # Load the file into a QMovie self.movie = QMovie(filename, QByteArray(), self) size = self.movie.scaledSize() self.setGeometry(200, 200, size.width(), size.height()) self.setWindowTitle(title) self.movie_screen = QLabel() # Make label fit the gif self.movie_screen.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.movie_screen.setAlignment(Qt.AlignCenter) # Create the layout main_layout = QVBoxLayout() main_layout.addWidget(self.movie_screen) self.setLayout(main_layout) # Add the QMovie object to the label self.movie.setCacheMode(QMovie.CacheAll) self.movie.setSpeed(100) self.movie_screen.setMovie(self.movie) self.movie.start()
def add_loading_widgets(self, children): # Generate list if only one item was given if not type(children) is list: item_list = [] item_list.append(children) children = item_list # Add loading widgets to tree items for child in children: if child.tree_item == None: return # Create loading widget load_widget = QtGui.QLabel() load_widget.resize(50,50) #load_widget.setMaximumSize(50,50) load_widget.setStyleSheet("QLabel { background-color: transparent; }") # Create animation load_anim = QMovie(self.datahandler.datapath("ui/images/loading_tree.gif"), "GIF", load_widget) load_anim.setCacheMode(QMovie.CacheAll) load_anim.setSpeed(150) load_anim.setScaledSize(QtCore.QSize(50,50)) # Add to data model and tree child.set_load_widget(load_widget, load_anim) self.tree.setItemWidget(child.tree_item, 1, load_widget)
class ImagePlayer(QWidget): def __init__(self, filename, title, parent=None): QWidget.__init__(self, parent) # Load the file into a QMovie self.movie = QMovie(filename, QByteArray(), self) print(filename) size = self.movie.scaledSize() self.setGeometry(200, 200, size.width(), size.height()) self.setWindowTitle(title) self.movie_screen = QLabel() # Make label fit the gif self.movie_screen.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.movie_screen.setAlignment(Qt.AlignCenter) self.btn_ex = QPushButton() self.btn_ex.setFixedWidth(100) self.btn_ex.setFixedHeight(100) # self.btn_ex.setIcon(QIcon("image/ex_stu.gif")) self.btn_ex.setStyleSheet("background-color: rgba(255,255,255,20);") self.btn_ex.setIcon(QIcon("image/smile.png")) self.btn_ex.setIconSize(QSize(80,80)) self.btn_ex.setFlat(True) popMenu = QMenu(self) entry1 = popMenu.addAction("正确") # self.connect(entry1,SIGNAL('triggered()'), lambda item=item[0]: self.answerRight(item)) entry2 = popMenu.addAction("错误") # self.connect(entry2,SIGNAL('triggered()'), lambda item=item[0]: self.answerWrong(item)) entry3 = popMenu.addAction("替换") # self.connect(entry3,SIGNAL('triggered()'), lambda item=item[0]: self.resetStudent(item)) self.btn_ex.setMenu(popMenu) # Create the layout main_layout = QVBoxLayout() main_layout.addWidget(self.movie_screen) # main_layout.addWidget(self.btn_ex) self.setLayout(main_layout) # Add the QMovie object to the label self.movie.setCacheMode(QMovie.CacheAll) # self.movie.setSpeed(100) self.movie_screen.setMovie(self.movie) self.movie_screen.setLayout(QHBoxLayout()) self.movie_screen.layout().addWidget(self.btn_ex) popMenu = QMenu(self) entry1 = popMenu.addAction("正确") # self.movie_screen.setMenu(popMenu) self.movie.start()
class UpdateInstallProgressDialog(QDialog): def __init__(self, parent=None): QDialog.__init__(self, parent) self.ui = Ui_UpdateInstallProgressDialog() self.ui.setupUi(self) # Swap out the label with the gif to a movie that will actually display # it correctly. self.window = self.ui.updateIconLabel self.movie = QMovie(':/icons/icons/update-in-progress.gif', QByteArray(), self) # Run the GIF self.movie.setCacheMode(QMovie.CacheAll) self.movie.setSpeed(100) self.window.setMovie(self.movie) self.movie.start()
def setStatus(self,status,message='',tooltip=None): '''Sets indicator icon and statusbar message''' self.parent.statusbar.showMessage(message) self.parent.statusbar.setToolTip(tooltip if tooltip else '') #progress loc = os.path.abspath(os.path.join(IMG_LOC,self.imgset[status])) #loc = os.path.abspath(os.path.join(os.path.dirname(__file__),self.parent.IMG_LOC,self.imgset[status])) self.progressbar.setVisible(status in (self.STATUS.BUSY, self.STATUS.CLEAN)) #icon anim = QMovie(loc, QByteArray(), self) anim.setScaledSize(QSize(self.IMG_WIDTH,self.IMG_HEIGHT)) anim.setCacheMode(QMovie.CacheAll) anim.setSpeed(self.IMG_SPEED) self.view.clear() self.view.setMovie(anim) anim.start() self.view.repaint() QApplication.processEvents(QEventLoop.AllEvents)
class MuteButtonLabel(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) #self.setFixedSize(CustomSize) self.movie_screen = QLabel() self.movie_screen.setFixedSize(CustomSize) self.movie_screen.setAlignment(Qt.AlignLeft) main_layout = QVBoxLayout() main_layout.addWidget(self.movie_screen) self.setLayout(main_layout) self.muted = False #self.unmute() # this is for testpurpose only def unmute(self): """start animation""" self.movie = QMovie(":/unmute.gif", QByteArray(), self) self.movie.setScaledSize(CustomSize*0.7) self.movie.setCacheMode(QMovie.CacheAll) self.movie.setSpeed(100) self.movie_screen.setMovie(self.movie) self.muted = False #print("Emitted 'sig_unmute'") self.emit(SIGNAL("sig_unmute")) self.movie.start() def show_unmute(self): self.movie = QMovie(":/unmute.gif", QByteArray(), self) self.movie.setScaledSize(CustomSize*0.7) self.movie.setCacheMode(QMovie.CacheAll) self.movie.setSpeed(100) self.movie_screen.setMovie(self.movie) self.muted = False self.movie.start() def mute(self): """stop the animation""" self.movie = QMovie(":/mute.gif", QByteArray(), self) self.movie.setScaledSize(CustomSize*0.7) self.movie.setCacheMode(QMovie.CacheAll) self.movie.setSpeed(100) self.movie_screen.setMovie(self.movie) self.muted = True #print("Emitted 'sig_mute'") self.emit(SIGNAL("sig_mute")) self.movie.start() def toggleMute(self): if self.muted: self.unmute() else: self.mute() def mousePressEvent(self, QMouseEvent): self.toggleMute() QMouseEvent.accept()
def __init__(self, visualization, parent_widget = None): QWidget.__init__(self, parent_widget) self.inGui = False self.visualization = visualization size = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.widgetLayout = QGridLayout(self) self.setSizePolicy(size) self.scroll = QScrollArea() file_path = self.visualization.get_file_path() self.label = QLabel() movie = QMovie(QString(file_path), QByteArray(), self) movie.setCacheMode(QMovie.CacheAll) self.label.setMovie(movie) movie.start() self.scroll.setWidget(self.label) self.widgetLayout.addWidget(self.scroll) self.tabIcon = QIcon(":/Images/Images/map.png") self.tabLabel = visualization.table_name
def __init__(self, visualization, parent_widget=None): QWidget.__init__(self, parent_widget) self.inGui = False self.visualization = visualization size = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.widgetLayout = QGridLayout(self) self.setSizePolicy(size) self.scroll = QScrollArea() file_path = self.visualization.get_file_path() self.label = QLabel() movie = QMovie(QString(file_path), QByteArray(), self) movie.setCacheMode(QMovie.CacheAll) self.label.setMovie(movie) movie.start() self.scroll.setWidget(self.label) self.widgetLayout.addWidget(self.scroll) self.tabIcon = QIcon(":/Images/Images/map.png") self.tabLabel = visualization.table_name
class MuWizard(QWizard): def __init__(self, R=None, parent=None): QWizard.__init__(self, parent) self.R = R self.data = None self.addPage(self.introPage()) self.addPage(self.loadPage()) self.addPage(self.modelsPage()) self.addPage(self.resultsPage()) self.setWindowTitle('Wizard of muScale') self.setPixmap(QWizard.LogoPixmap, QPixmap(RES + ICONS + LOGO)) self.setStyleSheet('QWizard {' + GRADIENT +'}\ QPushButton {\ color: #333;\ border: 1px solid #555;\ border-radius: 11px;\ padding: 2px;\ background: qradialgradient(cx: 0.3, cy: -0.4,\ fx: 0.3, fy: -0.4,\ radius: 1.35, stop: 0 #fff, stop: 1 #888);\ min-width: 80px;}\ QPushButton:hover {\ color: #fff;\ background: qradialgradient(cx: 0.3, cy: -0.4,\ fx: 0.3, fy: -0.4,\ radius: 1.35, stop: 0 #fff, stop: 1 #bbb);}\ QPushButton:pressed {\ color: #800;\ background: qradialgradient(cx: 0.4, cy: -0.1,\ fx: 0.4, fy: -0.1,\ radius: 1.35, stop: 0 #fff, stop: 1 #ddd);}\ QPushButton:checked {\ background: qradialgradient(cx: 0.4, cy: -0.1,\ fx: 0.4, fy: -0.1,\ radius: 1.35, stop: 0 #fff, stop: 1 #ddd);}\ QComboBox {\ color: #333;\ border: 1px solid #555;\ border-radius: 11px;\ padding: 1px 18px 1px 3px;\ background: qradialgradient(cx: 0.3, cy: -0.4,\ fx: 0.3, fy: -0.4,\ radius: 1.35, stop: 0 #fff, stop: 1 #888);\ min-width: 20px;}\ QComboBox:hover {\ color: #fff;\ background: qradialgradient(cx: 0.3, cy: -0.4,\ fx: 0.3, fy: -0.4,\ radius: 1.35, stop: 0 #fff, stop: 1 #bbb);}\ QComboBox::down-arrow {\ image: url(' + RES + ICONS + ARROW_DOWN + ');}\ QComboBox::down-arrow:on {\ top: 1px;\ left: 1px;}\ QComboBox::drop-down {\ subcontrol-origin: padding;\ subcontrol-position: top right;\ width: 15px;\ border-left-width: 1px;\ border-left-color: darkgray;\ border-left-style: solid;\ border-top-right-radius: 3px;\ border-bottom-right-radius: 3px;}\ QToolButton {\ color: #333;\ border: 1px solid #555;\ border-radius: 11px;\ padding: 2px;\ background: qradialgradient(cx: 0.3, cy: -0.4,\ fx: 0.3, fy: -0.4,\ radius: 1.35, stop: 0 #fff, stop: 1 #888);\ min-width: 20px;}\ QToolButton:hover {\ color: #fff;\ background: qradialgradient(cx: 0.3, cy: -0.4,\ fx: 0.3, fy: -0.4,\ radius: 1.35, stop: 0 #fff, stop: 1 #bbb);}\ QToolButton:pressed {\ background: qradialgradient(cx: 0.4, cy: -0.1,\ fx: 0.4, fy: -0.1,\ radius: 1.35, stop: 0 #fff, stop: 1 #ddd);}\ QToolButton:checked {\ background: qradialgradient(cx: 0.4, cy: -0.1,\ fx: 0.4, fy: -0.1,\ radius: 1.35, stop: 0 #fff, stop: 1 #ddd);}') def introPage(self): intro = QWizardPage() intro.setTitle('Hello and welcome') label = QLabel('''This is a wizard. Now you're ready to forecast some time series! ''') label.setWordWrap(True) layout = QVBoxLayout() layout.addWidget(label) intro.setLayout(layout) return intro def loadPage(self): load = WizardPageEx('loadCheck') load.setTitle('Initial data') pathLbl = QLabel("<font style='color: gray'>Specify the file with time series to forecast:</font>") loadLbl = QLabel("<font style='color: gray'>Click</font>") loadLbl.setAlignment(Qt.AlignCenter) self.path = QLineEdit() self.path.setPlaceholderText('path to file') getPath = QToolButton() getPath.setText('...') self.resultLbl = QLabel() self.resultLbl.setAlignment(Qt.AlignCenter) self.resultLbl.hide() self.preview = QLabel() self.preview.setAlignment(Qt.AlignCenter) self.preview.setWordWrap(True) self.preview.hide() self.preview.setAttribute(Qt.WA_Hover) self.filter = Filter() self.preview.installEventFilter(self.filter) getPath.clicked.connect(self.loadData) layout = QGridLayout() layout.addWidget(pathLbl, 0, 0) layout.addWidget(loadLbl, 0, 1) layout.addWidget(self.path, 1, 0) layout.addWidget(getPath, 1, 1) layout.addWidget(self.resultLbl, 2, 0, 1, 2) layout.addWidget(self.preview, 3, 0, 1, 2) load.setLayout(layout) load.previewSeries = SeriesPreview() self.previewSeries = load.previewSeries # to be able to reference from class namespace self.loadCheck = load.check return load def modelsPage(self): models = WizardPageEx('modelCheck') models.setTitle('Forecast') lbl = QLabel("<font style='color: gray'>Forecast horizon:</font>") self.steps = QSpinBox() self.steps.setRange(MIN_FORECAST, MAX_FORECAST) self.steps.setValue(10) self.start = QPushButton('Forecast') self.start.clicked.connect(self.modelling) self.custom = QPushButton('Advanced') self.processing = QLabel() self.gifLoading = QMovie(RES + ICONS + PROGRESS, QByteArray(), self) self.gifLoading.setCacheMode(QMovie.CacheAll) self.gifLoading.setSpeed(100) self.processing.setMovie(self.gifLoading) self.processing.setAlignment(Qt.AlignCenter) self.processing.hide() self.status = QLabel() self.status.setAlignment(Qt.AlignCenter) self.status.hide() layout = QGridLayout() layout.addWidget(lbl, 0, 0) layout.addWidget(self.steps, 0, 1) layout.addWidget(self.start, 0, 2) layout.addWidget(self.custom, 0, 3) layout.addWidget(self.status, 1, 0, 1, 4) layout.addWidget(self.processing, 2, 0, 1, 4) models.setLayout(layout) self.customOpt = CustomOption() self.custom.clicked.connect(self.customOpt.show) self.modelCheck = models.check return models def resultsPage(self): results = QWizardPage() results.setFinalPage(True) results.setTitle('Results') self.graph = QLabel("<font style='font-size: 16px;'>Plot</font>") self.export = QLabel("<font style='font-size: 16px;'>Export</font>") self.showData = QLabel("<font style='font-size: 16px;'>Data</font>") self.plotResult = MplWidget(None) self.plotResult.canvas.fig.set_facecolor('white') self.resData = QLabel('') self.resData.setAlignment(Qt.AlignCenter) self.resData.setWordWrap(True) self.resData.hide() self.resFilter = ResFilter() self.resLayout = QVBoxLayout() self.resLayout.addWidget(self.export) self.resLayout.addWidget(self.graph) self.resLayout.addWidget(self.showData) self.resLayout.addWidget(self.plotResult) self.resLayout.addWidget(self.resData) self.plotResult.hide() for index in range(0, self.resLayout.count()): try: self.resLayout.itemAt(index).widget().setAlignment(Qt.AlignCenter) self.resLayout.itemAt(index).widget().setStyleSheet('QLabel { color: gray; }') self.resLayout.itemAt(index).widget().setAttribute(Qt.WA_Hover) self.resLayout.itemAt(index).widget().installEventFilter(self.resFilter) except Exception: pass self.resLayout.setAlignment(Qt.AlignCenter) self.resLayout.setSpacing(60) results.setLayout(self.resLayout) return results #---- actions ----# def loadData(self): fileName = unicode(QFileDialog.getOpenFileName(self, 'Open text file', RES)) if fileName: self.resultLbl.hide() self.preview.hide() if DataParser.istextfile(fileName): self.data = DataParser.getTimeSeriesFromTextData(data=open(fileName, 'r').read()) if len(self.data[0]) > DATA_LOW_LIMIT: self.resultLbl.setText("<font style='color: gray'>Success! Loaded<b> " + str(len(self.data[0])) + '</b> values, errors: <b>' + str( self.data[1]) + '</b></font>') self.resultLbl.show() self.path.setText(fileName) previewLength = 40 self.preview.setText("<font style='color: gray'><b>Preview:</b> "+ ' '.join( [str(e) for e in self.data[0][:previewLength]]) + "...</font>") self.previewSeries.updateData(self.data) self.preview.show() self.loadCheck.setChecked(True) else: self.resultLbl.setText("<font style='color: gray'>Not enough values to form data series.</font>") self.resultLbl.show() else: self.resultLbl.setText("<font style='color: gray'>Specified file is binary file!</font>") self.resultLbl.show() def modelling(self): self.processing.show() self.gifLoading.start() self.status.setText('') statusText = u"<font style='color: gray'>" # decomposition # if self.customOpt.options['enable']: self.signalEx = self.customOpt.options['signal'] self.wavelet = pywt.Wavelet(self.customOpt.options['wavelet']) wLevel = self.customOpt.options['lvls'] - 1 maxLevel = pywt.dwt_max_level(len(self.data[0]), self.wavelet) if wLevel > maxLevel: wLevel = maxLevel self.wInitialCoefficients = pywt.wavedec(self.data[0], self.wavelet, level=wLevel, mode=self.signalEx) self.wCoefficients = self.wInitialCoefficients else: self.signalEx = pywt.MODES.sp1 selected = select_wavelet(self.data[0], self.R) index = max(selected) self.wavelet = pywt.Wavelet(selected[index][1]) wLevel = calculate_suitable_lvl(self.data[0], self.wavelet, self.R, swt=False) self.wInitialCoefficients = pywt.wavedec(self.data[0], self.wavelet, level=wLevel, mode=self.signalEx) self.wCoefficients = self.wInitialCoefficients statusText += 'Wavelet: <b>' + self.wavelet.family_name + \ '</b> (' + self.wavelet.name + ', ' + self.wavelet.symmetry + ', orthogonal: ' + \ str(self.wavelet.orthogonal) + ')<br/>' statusText += 'Discrete Wavelet Transfom: <b>' + str(wLevel + 1) + ' levels</b><br/>' # models # options = {} options['multi'] = True options['fractal'] = False options['ljung'] = False self.models = auto_model(self.wCoefficients, self.R, options, self.data[0]) statusText += '<br/>Selected models:<br/>' for lvl, model in self.models.iteritems(): statusText += str(lvl) + '. <b>' + model.enumname.replace('_', ' ') + '</b><br/>' # forecasting # try: frequency = self.customOpt.options['frequency'] except Exception: frequency = 8 aic = False options['hw_gamma'] = True options['hw_model'] = 'additive' options['hw_period'] = frequency options['ar_aic'] = aic options['ar_method'] = 'burg' options['ar_order'] = 50 options['arima_auto'] = False options['arima_nons'] = True options['arima_nons_order'] = [6, 0, 9] options['arima_seas'] = True options['arima_seas_order'] = [9, 0, 1] options['lsf_aic'] = aic options['lsf_order'] = 30 options['ets_auto'] = aic options['ets_period'] = frequency options['sts_type'] = 'trend' options['append_fit'] = True self.multi_model_thread = MultiModelThread(self.models, self.wCoefficients, self.R, self.steps.value(), options,) self.multi_model_thread.done.connect(self.multiForecastFinished) self.multi_model_thread.start() statusText += '<br/>Forecasting...' self.status.setText(statusText) self.status.show() def multiForecastFinished(self, results): self.forecast = results self.gifLoading.stop() self.processing.hide() self.status.setText('<br/>'.join(str(self.status.text()).split('<br/>')[:-1]) + '<br/>Forecast complete.') self.modelCheck.setChecked(True) #---- results -----# def togglePlot(self): if self.plotResult.isVisible(): self.plotResult.hide() self.export.show() self.showData.show() self.resLayout.setSpacing(60) else: self.updateGraph() self.plotResult.show() self.export.hide() self.showData.hide() self.resLayout.setSpacing(5) def toggleData(self): if self.resData.isVisible(): self.export.show() self.graph.show() self.showData.show() self.resData.hide() self.resLayout.setSpacing(60) self.adjustSize() else: self.plotResult.hide() self.graph.hide() self.export.hide() self.showData.show() self.resData.show() self.resLayout.setSpacing(5) res = self.inverseWT() max = len(self.data[0]) - 1 resText = '<table border="0" align="center" style="border-style: groove;">' resText += '<tr><td align="center"><i>Initial</i></td><td align="center"><i>Forecast</i></td></tr>' resText += '<tr><td align="center">...</td><td></td></tr>' table = zip(self.data[0][max-10:max], res[max-10:max]) for i, j in table: resText += '<tr>' resText += '<td align="center">' + str(i) + '</td>' resText += '<td align="center">' + str(j) + '</td>' resText += '</tr>' for e in res[max+1:max+10]: resText += '<tr>' resText += '<td align="center"></td>' resText += '<td align="center">' + str(e) + '</td>' resText += '</tr>' resText += '<tr><td align="center"></td><td align="center">...</td></tr>' resText += '</table>' self.resData.setText(resText) self.adjustSize() def inverseWT(self): return pywt.waverec(update_dwt([e [1] for e in self.forecast], self.wavelet, self.signalEx), self.wavelet, mode=self.signalEx) def updateGraph(self): self.plotResult.updatePlot(self.inverseWT(), label='Simulation', color='r') self.plotResult.updatePlot(self.data[0], label='Time series', color='b') def exportToXls(self): # opening file dialog fileName = QFileDialog.getSaveFileName(self, 'Save as', RES, 'Microsoft Excel Spreadsheet (*.xls)') if fileName.count() > 0: try: COLUMN_WIDTH = 3000 alignment = Alignment() alignment.horizontal = Alignment.HORZ_CENTER alignment.vertical = Alignment.VERT_CENTER borders = Borders() borders.left = Borders.THIN borders.right = Borders.THIN borders.top = Borders.THIN borders.bottom = Borders.THIN style = XFStyle() style.alignment = alignment style.borders = borders font = Font() font.bold = True headerStyle = XFStyle() headerStyle.font = font separate = Borders() separate.left = Borders.THIN separate.right = Borders.DOUBLE separate.top = Borders.THIN separate.bottom = Borders.THIN separateStyle = XFStyle() separateStyle.borders = separate book = Workbook(encoding='utf-8') # modelling data dec_sheet = book.add_sheet('Data decomposition') # decomposition data # initial data column = 0 row = 0 dec_sheet.write(row, column, 'Time series', headerStyle) dec_sheet.col(column).width = COLUMN_WIDTH row += 1 for item in self.data[0]: dec_sheet.write(row, column, item, separateStyle) row += 1 # decomposition for lvl in self.wCoefficients: row = 0 column += 1 dec_sheet.write(row, column, 'Level' + str(column - 1), headerStyle) dec_sheet.col(column).width = COLUMN_WIDTH row += 1 for item in lvl: dec_sheet.write(row, column, item, style) row += 1 # decomposition graphs pass levels_sheet = book.add_sheet('Multiscale forecast') # levels data column = 0 for lvl in self.forecast: row = 0 levels_sheet.write(row, column, 'Level' + str(column), headerStyle) levels_sheet.col(column).width = COLUMN_WIDTH row += 1 for item in lvl[1]: levels_sheet.write(row, column, float(item), style) row += 1 column += 1 result_sheet = book.add_sheet('Results') # initial column = 0 row = 0 result_sheet.write(row, column, 'Initial data', headerStyle) result_sheet.col(column).width = COLUMN_WIDTH row += 1 for item in self.data[0]: result_sheet.write(row, column, item, separateStyle) row += 1 # forecast row = 0 column += 1 result_sheet.write(row, column, 'Forecast', headerStyle) result_sheet.col(column).width = COLUMN_WIDTH row += 1 for item in self.inverseWT(): result_sheet.write(row, column, item, style) row += 1 row = 0 column = 2 self.updateGraph() self.plotResult.saveFigure('forecast', format='bmp') result_sheet.insert_bitmap(RES + TEMP + 'forecast.bmp', row, column) # saving xls try: book.save(unicode(fileName)) except Exception: pass except Exception, e: pass
class MainWindow(QDialog): def __init__(self): QDialog.__init__(self) self.ui=Ui_Dialog() self.ui.setupUi(self) self.configFile, self.machinesData,configExists = localdata.loadData() self.UIfixes() self.fillTable() self.adaptToOS(self.customForClient) communication.listen(self) # we pass self to emmit a signal each time a # machine is found self.machinesItems = {} # for Bookeeping our table items self.table = self.ui.machinesTable #because too long name # buttons self.ui.generateClientButton.clicked.connect(self.runCompilingJob) self.ui.uploadButton.clicked.connect(self.prepareShipment) # Ui events self.connect(self,SIGNAL('droppedFile'),self.checkInput) self.connect(self,SIGNAL('updateStatus'),self.updateMachinesTable) self.connect(self,SIGNAL('toggleAnimation'),self.toggleWaiting) self.connect(self,SIGNAL('addMachines'),self.addDetectedMachine) self.ui.fileDropTextLine.editingFinished.connect(self.checkInput) self.table.cellDoubleClicked.connect(self.deleteMachine) self.ui.usernameTextBox.editingFinished.connect(self.saveConfig) self.ui.passwordTextBox.editingFinished.connect(self.saveConfig) machinesAlive(self.machinesItems) def getMachineItem(self,ip): return self.machinesItems[ip] def toggleWaiting(self): if self.movie.state() == 0: self.ui.fileDropTextLine.setFixedHeight(0) self.ui.movie_screen.setFixedHeight(26) self.movie.start() else: self.movie.stop() self.ui.fileDropTextLine.setFixedHeight(26) self.ui.movie_screen.setFixedHeight(0) def UIfixes(self): ''' Stuff you can't do on QtDesigner ''' # reimplementing drops self.ui.fileDropTextLine.__class__.dragMoveEvent = self.mydragMoveEvent self.ui.fileDropTextLine.__class__.dragEnterEvent =self.mydragEnterEvent self.ui.fileDropTextLine.__class__.dropEvent = self.myDropEvent # Waiting animation self.ui.movie_screen.setFixedHeight(0) self.movie = QMovie("loader.gif", QByteArray(), self) self.movie.setCacheMode(QMovie.CacheAll) self.movie.setSpeed(100) self.ui.movie_screen.setMovie(self.movie) if len(self.machinesData) != 0: # if the user already created clients.exe self.ui.tabWidget.setCurrentWidget(self.ui.serverTab) self.table.verticalHeader().setVisible(False) # QtDesigner miss this self.ui.passwordTextBox.setEchoMode(2) # how to do this on Qtdesigner? # darn it QtDesign get your stuff together if configExists: self.ui.usernameTextBox.setText(configFile['USERNAME']) self.ui.passwordTextBox.setText(configFile['PASSWORD']) def fillTable(self): for name,ip in self.machinesData.items(): rowCount = self.table.rowCount() nameItem = QTableWidgetItem(name) ipItem = QTableWidgetItem(self.machinesData[name]) statusItem = QTableWidgetItem('desconocido') self.table.insertRow(rowCount) self.table.setItem(rowCount,NAME,nameItem) self.table.setItem(rowCount,IP,ipItem) self.table.setItem(rowCount,STATUS,statusItem) self.machinesItems[ip] = ipItem #save QTableWidgetItem for later use self.sortTable() def addDetectedMachine(self,name,ip): if not self.machinesData.has_key(name): self.machinesData[name] = ip rowCount = self.table.rowCount() nameItem = QTableWidgetItem(name) ipItem = QTableWidgetItem(self.machinesData[name]) statusItem = QTableWidgetItem('conectada') self.table.insertRow(rowCount) self.table.setItem(rowCount,NAME,nameItem) self.table.setItem(rowCount,IP,ipItem) self.table.setItem(rowCount,STATUS,statusItem) self.machinesData.write() #and save our detected data to our machines dic self.machinesItems[ip] = ipItem #save QTableWidgetItem for later use def updateMachinesTable(self,item,isAlive=True,transferStatus=None): ''' item(QTableWidgetItem) : the computer in the table to modify isAlive(bool) : the computer's status on by default transferStatus(str) : the transfer status of the file ''' row = item.row() if isAlive == True: statusItem = QTableWidgetItem('conectada') else: statusItem = QTableWidgetItem('desconectada') return self.table.setItem(row,STATUS,statusItem) if transferStatus: transfer = QTableWidgetItem(transferStatus) else: transfer = QTableWidgetItem('Lista para recibir archivos') self.table.setItem(row,TRANSFER,transfer) def deleteMachine(self, row, column): self.table.selectRow(row) name = str(self.table.item(row,0).text()) ip = str(self.table.item(row,2).text()) del self.machinesItems[ip] self.table.removeRow(row) del self.machinesData[name] self.machinesData.write() def prepareShipment(self): if self.checkInput(): filename = str(self.ui.fileDropTextLine.text()) else: return start_new_thread(self.upload,(filename,)) def checkInput(self): text = self.ui.fileDropTextLine.text() if path.isfile(text): self.ui.fileDropTextLine.setStyleSheet("color: black;") return True else: self.ui.fileDropTextLine.setStyleSheet("color: red;") self.ui.fileDropTextLine.setText('Archivo invalido o inexistente') return False def getLocalIP(self): ''' yes a function is needed for this apparently there are many implementations, this one it is said it works with single lan boxes''' ip = gethostbyname(gethostname()) if ip.startswith('127'): print 'linux machine or offline machine ' return ip def mydragEnterEvent(self, event): if event.mimeData().hasUrls: event.accept() self.ui.fileDropTextLine.clear() else: event.ignore() def mydragMoveEvent(self, event): if event.mimeData().hasUrls: event.accept() else: event.ignore() def myDropEvent(self, event): ''' loads into our self.files set the dropped fil5e names and emit a signal to advertise the change''' if event.mimeData().hasUrls: event.setDropAction(Qt.CopyAction) event.accept() if len(event.mimeData().urls()) > 1: self.ui.fileDropTextLine.setText('Arraste un solo archivo') else: for url in event.mimeData().urls(): url = str(url.toLocalFile()) self.ui.fileDropTextLine.setText(url) self.emit(SIGNAL('droppedFile')) else: event.ignore() def keyPressEvent(self,ev): if ev.key() == Qt.Key_F5: print 'F5 pressed' self.ui.tabWidget.setCurrentWidget(self.ui.serverTab) communication.pingThem(self,self.machinesItems) if ev.key() == Qt.Key_F6: print 'F6 pressed' self.ui.tabWidget.setCurrentWidget(self.ui.serverTab) start_new_thread(self.sort,()) def sortTable(self): self.table.sortItems(IP,Qt.AscendingOrder)
class UiController: def __init__(self, controller, debug_mode, logger): self.controller = controller self.datahandler = controller.datahandler self.debug_mode = debug_mode self.logger = logger ### Main Window self.main_widget = QMainWindow() self.main_widget.setAttribute(Qt.WA_Maemo5StackedWindow) self.main_ui = Ui_DropN900Widget() self.main_ui.setupUi(self.main_widget) # Stacked layout for context switching self.stacked_layout = QtGui.QStackedLayout() self.main_ui.centralwidget.setLayout(self.stacked_layout) # Menu items self.action_transfers = QtGui.QAction("Transfers", self.main_widget) self.action_settings = QtGui.QAction("Settings", self.main_widget) self.action_sync = QtGui.QAction("Synchronize", self.main_widget) self.action_sync_photos = QtGui.QAction("Sync Media", self.main_widget) self.action_console = QtGui.QAction("Show Log", self.main_widget) self.action_about = QtGui.QAction("About", self.main_widget) self.action_exit = QtGui.QAction("Exit", self.main_widget) self.main_ui.menubar.addAction(self.action_transfers) self.main_ui.menubar.addAction(self.action_settings) self.main_ui.menubar.addAction(self.action_sync) self.main_ui.menubar.addAction(self.action_sync_photos) self.main_ui.menubar.addAction(self.action_console) self.main_ui.menubar.addAction(self.action_about) self.main_ui.menubar.addAction(self.action_exit) # Connects self.action_transfers.triggered.connect(self.show_transfer_widget) self.action_sync.triggered.connect(self.synchronize_now) self.action_sync_photos.triggered.connect(self.synchronize_now_photos) self.action_settings.triggered.connect(self.show_settings_widget) self.action_console.triggered.connect(self.show_console) self.action_about.triggered.connect(self.show_about) self.action_exit.triggered.connect(self.shut_down) ### Trusted Login Widget self.trusted_login_widget = QWidget() self.trusted_login_ui = Ui_TrustedLoginWidget() self.trusted_login_ui.setupUi(self.trusted_login_widget) self.trusted_login_ui.label_icon.setPixmap(QPixmap(self.datahandler.datapath("ui/images/dropn900_logo.png")).scaled(65,65)) # Connects self.trusted_login_ui.button_auth.clicked.connect(self.try_trusted_login) ### Manager Widget self.manager_widget = QWidget() self.manager_ui = Ui_ManagerWidget() self.manager_ui.setupUi(self.manager_widget) # Tree Controller tree = self.manager_ui.tree_widget self.tree_controller = TreeController(tree, self.manager_ui, self.controller, self.logger) # Hide public link elements on start self.manager_ui.button_copy_public_link.hide() self.manager_ui.button_open_public_link.hide() # Connects self.manager_ui.button_copy_public_link.clicked.connect(self.copy_item_link) self.manager_ui.button_open_public_link.clicked.connect(self.open_item_link) self.manager_ui.button_download.clicked.connect(self.item_download) self.manager_ui.button_upload.clicked.connect(self.item_upload) self.manager_ui.button_rename.clicked.connect(self.item_rename) self.manager_ui.button_remove.clicked.connect(self.item_remove) self.manager_ui.button_new_folder.clicked.connect(self.item_new_folder) self.manager_ui.sync_button.clicked.connect(self.synchronize_now) self.last_dl_location = None self.last_ul_location = None ### Console widget self.console_widget = QWidget(self.main_widget, Qt.Window) self.console_widget.setAttribute(Qt.WA_Maemo5StackedWindow) self.console_ui = Ui_ConsoleWidget() self.console_ui.setupUi(self.console_widget) self.console_ui.button_save.clicked.connect(self.save_log_to_file) self.console_ui.button_back.clicked.connect(self.hide_console) ### Settings widget self.settings_widget = None ### Fill stacked layout self.stacked_layout.addWidget(self.trusted_login_widget) self.stacked_layout.addWidget(self.manager_widget) self.stacked_layout.setCurrentWidget(self.trusted_login_widget) ### Loading Widget self.loading_widget = QWidget(self.manager_widget) self.loading_ui = Ui_LoadingWidget() self.loading_ui.setupUi(self.loading_widget) self.manager_ui.action_layout.insertWidget(3, self.loading_widget) self.loading_widget.hide() self.tree_controller.set_loading_ui(self.loading_ui) # Init loading animation self.loading_animation = QMovie(self.datahandler.datapath("ui/images/loading.gif"), "GIF", self.loading_ui.load_animation_label) self.loading_animation.setCacheMode(QMovie.CacheAll) self.loading_animation.setSpeed(150) self.loading_animation.setScaledSize(QtCore.QSize(48,48)) self.loading_ui.load_animation_label.setMovie(self.loading_animation) # Init hide timer and icons for information messages self.information_message_timer = QTimer() self.information_message_timer.setSingleShot(True) self.information_message_timer.timeout.connect(self.hide_information_message) self.information_icon_ok = QPixmap(self.datahandler.datapath("ui/icons/check.png")).scaled(24,24) self.information_icon_error = QPixmap(self.datahandler.datapath("ui/icons/cancel.png")).scaled(24,24) self.information_icon_queue = QPixmap(self.datahandler.datapath("ui/icons/queue.png")).scaled(24,24) ### About dialog self.about_dialog = AboutDialog(self) self.set_synching(False) def set_synching(self, syncing): self.manager_ui.sync_button.setVisible(not syncing) self.manager_ui.sync_label.setVisible(syncing) def set_settings_widget(self, settings_widget): self.settings_widget = settings_widget def set_transfer_widget(self, transfer_widget): self.transfer_widget = transfer_widget def synchronize_now(self): self.settings_widget.sync_now_clicked() def synchronize_now_photos(self): self.controller.sync_manager.sync_media() def show(self): # Nokia N900 screen resolution, full screen self.main_widget.resize(800, 480) self.main_widget.show() self.main_widget.showMaximized() def show_settings_widget(self): if self.settings_widget != None: if not self.settings_widget.isVisible(): self.settings_widget.show() self.settings_widget.check_settings() def show_transfer_widget(self): if self.settings_widget.isVisible(): self.settings_widget.hide() self.transfer_widget.show() def show_about(self): if not self.about_dialog.isVisible(): self.about_dialog.show() def show_note(self, message): QMaemo5InformationBox.information(None, QString(message), 0) def show_banner(self, message, timeout = 5000): QMaemo5InformationBox.information(None, QString(message), timeout) def show_loading_ui(self, message = "", loading = True): self.loading_ui.info_label.setText(message) self.loading_ui.info_label_icon.hide() self.thumb_was_visible = self.manager_ui.thumb_container.isVisible() self.manager_ui.thumb_container.hide() self.loading_widget.show() self.loading_ui.load_animation_label.setVisible(loading) if loading: self.loading_animation.start() else: self.loading_animation.stop() def show_information_ui(self, message, succesfull, timeout = 4000): self.loading_ui.load_animation_label.hide() self.thumb_was_visible = self.manager_ui.thumb_container.isVisible() if self.thumb_was_visible: self.manager_ui.thumb_container.hide() self.loading_ui.info_label.setText(message) if succesfull == None: icon = self.information_icon_queue elif succesfull: icon = self.information_icon_ok else: icon = self.information_icon_error self.loading_ui.info_label_icon.setPixmap(icon) self.loading_ui.info_label_icon.show() self.loading_widget.show() self.information_message_timer.start(timeout) def hide_loading_ui(self): if not self.information_message_timer.isActive(): self.loading_widget.hide() if self.loading_animation.state() == QMovie.Running: self.loading_animation.stop() def hide_information_message(self): self.loading_ui.info_label_icon.hide() self.hide_loading_ui() self.manager_ui.thumb_container.setVisible(self.thumb_was_visible) def try_trusted_login(self): self.trusted_login_ui.label_error.setText("") email = self.trusted_login_ui.line_edit_email.text() password = self.trusted_login_ui.line_edit_password.text() error = None if email.isEmpty(): error = "Email can't be empty!" elif email.count("@") != 1: error = "Invalid email, check your @ signs!" elif email.contains(" "): error = "Invalid email, can't have spaces!" elif password.isEmpty(): error = "Password can't be empty!" if error == None: self.show_banner("Authenticating...", 3000) self.set_trusted_login_info("Authenticating, please wait...") self.truested_email = self.datahandler.to_unicode(str(email.toUtf8())) self.trusted_password = self.datahandler.to_unicode(str(password.toUtf8())) QTimer.singleShot(100, self.do_trusted_login_networking) else: self.set_trusted_login_error(error) def set_trusted_login_error(self, error): self.trusted_login_ui.label_error.setStyleSheet("color: #9d1414;") self.trusted_login_ui.label_error.setText(error) self.truested_email = None self.trusted_password = None def set_trusted_login_info(self, info): self.trusted_login_ui.label_error.setStyleSheet("color: #149d2b;") self.trusted_login_ui.label_error.setText(info) def do_trusted_login_networking(self): self.controller.end_trusted_auth(self.truested_email.encode("utf-8"), self.trusted_password.encode("utf-8")) self.truested_email = None self.trusted_password = None def reset_trusted_login(self): self.trusted_login_ui.line_edit_email.clear() self.trusted_login_ui.line_edit_password.clear() self.trusted_login_ui.label_error.clear() def switch_context(self, view = None): widget = None if view == "trustedlogin": widget = self.trusted_login_widget if view == "manager": widget = self.manager_widget if view == "console": self.console_widget.show() if view == None and self.last_view != None: widget = self.last_view if widget != None: self.last_view = self.stacked_layout.currentWidget() self.stacked_layout.setCurrentWidget(widget) def get_selected_data(self): return self.tree_controller.selected_data # Signal handlers def shut_down(self): self.main_widget.close() def show_console(self): if self.console_widget.isVisible() == False: self.switch_context("console") else: self.hide_console() def hide_console(self): self.console_widget.hide() def save_log_to_file(self): filename = self.datahandler.get_data_dir_path() + "dropn900.log" log_string = str(self.console_ui.text_area.toPlainText()) try: log_file = open(filename, "w") log_file.write(log_string) log_file.close() self.show_banner("Log saved to " + filename) except IOError: self.logger.error("Could not open " + filename + " to save log") def browser_control_clicked(self): if self.controller.connected: self.switch_context() else: self.controller.end_auth() def copy_item_link(self): url = self.tree_controller.current_public_link if url == None: return self.datahandler.copy_url_to_clipboard(url) def open_item_link(self): url = self.tree_controller.current_public_link if url == None: return QDesktopServices.openUrl(QtCore.QUrl(url)) def item_download(self): data = self.get_selected_data() if data == None: return if self.datahandler.dont_show_dl_dialog == False: # This dialog shows sometimes strange stuff on maemo5 # It's a PyQt4 bug and its the best we got, you can cope with this if self.last_dl_location == None: self.last_dl_location = self.datahandler.get_data_dir_path() local_folder_path = QFileDialog.getExistingDirectory(self.manager_widget, QString("Select Download Folder"), QString(self.last_dl_location), QFileDialog.ShowDirsOnly|QFileDialog.HideNameFilterDetails|QFileDialog.ReadOnly) if local_folder_path.isEmpty(): return py_unicode_path = self.datahandler.to_unicode(str(local_folder_path.toUtf8())) self.last_dl_location = py_unicode_path store_path = py_unicode_path + "/" + data.name else: dir_check = QDir(self.datahandler.get_data_dir_path()) if not dir_check.exists(): self.show_note("Cannot download, destination " + self.datahandler.get_data_dir_path() + " does not exist. Please set a new folder in settings.") return store_path = self.datahandler.get_data_dir_path() + data.name self.controller.connection.get_file(data.path, data.root, store_path, data.get_size(), data.mime_type) def item_upload(self): data = self.get_selected_data() if data == None or not data.is_folder(): return # This dialog shows sometimes strange stuff on maemo5 # It's a PyQt4 bug and its the best we got, you can cope with this if self.last_ul_location == None: self.last_ul_location = self.datahandler.get_data_dir_path() local_file_path = QFileDialog.getOpenFileName(self.manager_widget, QString("Select File for Upload"), QString(self.last_ul_location)) if local_file_path.isEmpty(): return py_unicode_path = self.datahandler.to_unicode(str(local_file_path.toUtf8())) self.last_ul_location = py_unicode_path[0:py_unicode_path.rfind("/")] self.controller.connection.upload_file(data.path, data.root, py_unicode_path) def item_rename(self): data = self.get_selected_data() if data == None: return # Get new name from user old_name = data.get_name() keyword = "file" if not data.is_folder() else "folder" new_name, ok = QInputDialog.getText(None, "Renaming " + keyword, "Give new name for " + keyword + " " + old_name, QtGui.QLineEdit.Normal, old_name) if not ok: return # Validate with QString if not self.is_name_valid(new_name, keyword): return # Make QString to python 'unicode' new_name = self.datahandler.to_unicode(str(new_name.toUtf8())) if old_name == new_name: return # Extension will be lost, ask user if he wants to leave it q_old_name = QtCore.QString(old_name) if q_old_name.contains("."): if not new_name.contains("."): format = old_name[q_old_name.lastIndexOf("."):] confirmation = QMessageBox.question(None, "Extension missing", "Do you want to append the original '" + format + "' extensions to the filename '" + new_name + "'?", QMessageBox.Yes, QMessageBox.No) if confirmation == QMessageBox.Yes: new_name.append(format) # Get final new path and rename if data.parent == "/": new_name = data.parent + new_name else: new_name = data.parent + "/" + new_name self.controller.connection.rename(data.root, data.path, new_name, data) def item_remove(self): data = self.get_selected_data() if data == None: return if data.is_folder(): confirmation = QMessageBox.question(None, "Remove folder verification", "Are you sure you want to remove the entire folder " + data.get_name() +"?", QMessageBox.Yes, QMessageBox.Cancel) else: confirmation = QMessageBox.question(None, "Remove file verification", "Are you sure you want to remove " + data.get_name() +"?", QMessageBox.Yes, QMessageBox.Cancel) if confirmation == QMessageBox.Yes: self.controller.connection.remove_file(data.root, data.path, data.parent, data.is_folder()) def item_new_folder(self): data = self.get_selected_data() if data == None: return if not data.is_folder(): return full_create_path = data.path + "/" new_folder_name, ok = QInputDialog.getText(None, "Give new folder name", "") if not ok: return # Validate QString if not self.is_name_valid(new_folder_name, "folder"): return # Make QString to python unicode new_folder_name = self.datahandler.to_unicode(str(new_folder_name.toUtf8())) full_create_path = data.path + "/" + new_folder_name self.controller.connection.create_folder(data.root, full_create_path, new_folder_name, data.path) def is_name_valid(self, name, item_type): if name.isEmpty() or name.isNull(): return False if name.contains("/"): self.show_information_ui("Cant use / in new " + item_type + " name", False) return False if name.contains("\\"): self.show_information_ui("Cant use \ in new " + item_type + " name", False) return False if name.startsWith(" "): self.show_information_ui("New " + item_type + " name cant start with a space", False) return False if name.endsWith(" "): self.show_information_ui("New " + item_type + " name cant end with a space", False) return False return True