def __init__(self, parent, title='', msg = '', width=None): QDialog.__init__(self, parent) self.setWindowTitle(title) self.setPalette(white_palette) sizer = QVBoxLayout() self.setLayout(sizer) texte = QTextEdit(self) texte.setPlainText(msg) texte.setMinimumHeight(500) texte.setReadOnly(True) if width is None: texte.setLineWrapMode(QTextEdit.NoWrap) doc = texte.document() width = doc.idealWidth() + 4*doc.documentMargin() texte.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) texte.setMinimumWidth(width) sizer.addWidget(texte) boutons = QHBoxLayout() boutons.addStretch() ok = QPushButton('OK', clicked=self.close) boutons.addWidget(ok) boutons.addStretch() sizer.addLayout(boutons)
class PastMessagesView(QWidget): def __init__(self, parent=None): super(PastMessagesView, self).__init__(parent) layout = QVBoxLayout(self) self.text = QTextEdit() self.text.setReadOnly(True) self.text.setLineWrapMode(QTextEdit.WidgetWidth) layout.addWidget(self.text) self.setLayout(layout) def AddMessageAsHtml(self, html): self.text.insertHtml(html)
def on_pb_show_warnings_released(self): # show a dialog box with only the warnings from the conversion win = QDialog(self) win.resize(self.size() * 0.85) layout = QVBoxLayout() txt = QTextEdit(win) txt.setLineWrapMode(txt.NoWrap) txt.document().setPlainText('\n'.join(self.converter.warnings)) pb = QPushButton('Close') self.connect(pb, SIGNAL('released()'), win.accept) layout.addWidget(txt) layout.addWidget(pb) win.setLayout(layout) win.exec_()
def window_msgCheckCreatePluginWidget(self,parent,plugin_object,p_name): sw = None try: sw = plugin_object.create_widget(parent) except: stringOut = StringIO() traceback.print_exc(None, stringOut) getCoreLogger().exception("while including plugin %s with options: %s %s", p_name, str(plugin_object.options), str(sys.exc_info())) sw = QTextEdit(parent) #sw.set_size_request(400,200) sw.setLineWrapMode(QTextEdit.WidgetWidth) sw.setPlainText(stringOut.getvalue()) stringOut.close() return sw
class lunch_menu(iface_gui_plugin): def __init__(self): super(lunch_menu, self).__init__() self.options = [(("no_proxy", "Don't use proxy server"),False), (("url", "URL"),"http://lunchinator.de/files/menu_dummy.txt")] def activate(self): iface_gui_plugin.activate(self) def deactivate(self): iface_gui_plugin.deactivate(self) def create_widget(self, parent): from PyQt4.QtGui import QTextEdit, QSizePolicy from lunchinator.callables import AsyncCall self._textview = QTextEdit(parent) self._textview.setLineWrapMode(QTextEdit.WidgetWidth) self._textview.setReadOnly(True) self._textview.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) AsyncCall(getValidQtParent(), self.logger, self._downloadText, self._updateText, self._errorDownloadingText)() return self._textview def _downloadText(self): if self.options["no_proxy"]: hdr = {'User-Agent': 'Mozilla/5.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'} req = urllib2.Request(self.options["url"], headers=hdr) proxy_handler = urllib2.ProxyHandler({}) opener = urllib2.build_opener(proxy_handler) with contextlib.closing(opener.open(req)) as u: return u.read() resp = urllib2.urlopen(self.options["url"]) return resp.read() @loggingFunc def _updateText(self, txt): self._textview.setPlainText(txt) @loggingFunc def _errorDownloadingText(self, msg): self._textview.setPlainText("Error downloading text: " + msg) def add_menu(self,menu): pass
class InfoDialog(QMainWindow): def __init__(self, parent=None, info_data=''): QMainWindow.__init__(self) self.info_data = info_data self.confirmed = False self.resize(700, 400) self.initUI() def initUI(self): cw = QWidget() self.setCentralWidget(cw) layout_main = QVBoxLayout() layout_main.setSpacing(5) self.setWindowTitle('New SSH logins to Localhost') ## Info self.info = QTextEdit() self.info.setReadOnly(True) self.info.setLineWrapMode(QTextEdit.NoWrap) self.info.append(self.info_data) layout_main.addWidget(self.info, 1) # confirm button self.btn_confirm = QPushButton('Confirm') self.btn_confirm.pressed.connect(self.confirm) layout_main.addWidget(self.btn_confirm) ## add stretch layout_main.addStretch() ## Setup layout cw.setLayout(layout_main) self.show() def confirm(self): self.confirmed = True self.close() def getConfirmed(self): return self.confirmed
def __init__(self, parent): QWidget.__init__(self, parent) self.parent = parent sizer = QVBoxLayout() texte = QTextEdit(self) with open(path2("%/wxgeometrie/doc/license.txt"), "r") as f: msg = f.read().decode("utf8") texte.setPlainText(msg) texte.setMinimumHeight(500) texte.setReadOnly(True) texte.setLineWrapMode(QTextEdit.NoWrap) doc = texte.document() width = doc.idealWidth() + 4 * doc.documentMargin() texte.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) texte.setMinimumWidth(width) sizer.addWidget(texte) self.setLayout(sizer)
def __init__(self, parent): QWidget.__init__(self, parent) self.parent = parent sizer = QVBoxLayout() texte = QTextEdit(self) with open(path2("%/wxgeometrie/doc/changelog.txt"), "r") as f: msg = f.read().decode("utf8").replace("\n", "<br>") titre = u"<b>Changements apportés par la version %s :</b>" % param.version msg = "<br>".join((titre, "", msg)) texte.setHtml(msg) texte.setMinimumHeight(500) texte.setReadOnly(True) texte.setLineWrapMode(QTextEdit.NoWrap) doc = texte.document() width = doc.idealWidth() + 4 * doc.documentMargin() texte.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) texte.setMinimumWidth(width) sizer.addWidget(texte) self.setLayout(sizer)
def show(self, what, title=None, plain=False): try: from PyQt4.QtGui import QTextEdit, QTextCursor except ImportError: g.es("Need Qt for show command") return if not title: title = what.split('\n', 1)[0].strip() te = QTextEdit() te.setReadOnly(True) if plain: te.setText(what) else: te.setHtml("<pre>%s</pre>" % what) te.setLineWrapMode(QTextEdit.NoWrap) te.resize(800, 600) te.setWindowTitle(title) te.moveCursor(QTextCursor.End) te.show() self.popups.append(te)
class MainWindow(QMainWindow): """ class MainWindow for the gui of dokueddy """ def __init__(self, config, parent=None): """ Constructor for class MainWindow @param config: dokueddy configuration """ QMainWindow.__init__(self) self.config = config self.setGeometry( self.config.settings['app_x'], self.config.settings['app_y'], self.config.settings['app_w'], self.config.settings['app_h'] ) self.setWindowTitle( self.config.settings['appname'] + ' - Version: ' + self.config.settings['appversion'] ) globalFont = QFont( self.config.settings['fontfamily'], self.config.settings['pointsize'] ) self.statusbar = self.statusBar() self.center() self.exit = QAction('Quit Dokueddy', self) self.menubar = QMenuBar(None) self.file = self.menubar.addMenu('&File') self.file.addAction(self.exit) self.setMenuBar(self.menubar) self.save = QAction(QIcon('../resources/icons/save_edit.gif'), 'Save current page', self) self.save.setShortcut('Ctrl+S') self.save.setDisabled(True) self.fontBold = QAction(QIcon('../resources/icons/tag_bold.png'), 'Bold text', self) self.fontItalic = QAction(QIcon('../resources/icons/tag_i.png'), 'Italic text', self) self.fontH1 = QAction(QIcon('../resources/icons/tag_h1.png'), 'Heading 1', self) self.fontH2 = QAction(QIcon('../resources/icons/tag_h2.png'), 'Heading 2', self) self.fontH3 = QAction(QIcon('../resources/icons/tag_h3.png'), 'Heading 3', self) self.fontH4 = QAction(QIcon('../resources/icons/tag_h4.png'), 'Heading 4', self) self.fontH5 = QAction(QIcon('../resources/icons/tag_h5.png'), 'Heading 5', self) self.search = QAction(QIcon('../resources/icons/magnify.png'), 'Search for', self) self.toolbar = self.addToolBar('Toolbar') self.toolbar.addAction(self.save) self.toolbar.addSeparator() self.toolbar.addAction(self.fontBold) self.toolbar.addAction(self.fontItalic) self.toolbar.addAction(self.fontH1) self.toolbar.addAction(self.fontH2) self.toolbar.addAction(self.fontH3) self.toolbar.addAction(self.fontH4) self.toolbar.addAction(self.fontH5) self.toolbar.addAction(self.search) self.toolbar.setMaximumHeight(24) self.serverLabel = QLabel() self.serverLabel.setText('Serveraddress:') self.userLabel = QLabel() self.userLabel.setText('Username:'******'Password:'******'serverAddress']) self.userLineEdit = QLineEdit() self.userLineEdit.setMaximumSize(150, 35) self.userLineEdit.setText(self.config.settings['user']) self.passwdLineEdit = QLineEdit() self.passwdLineEdit.setMaximumSize(150, 35) self.passwdLineEdit.setEchoMode(QLineEdit.Password) self.connectButton = QPushButton('Connect', self) self.connectButton.setMaximumSize(100, 35) self.quitButton = QPushButton('Quit', self) self.quitButton.setMaximumSize(100, 35) self.listView = QListView(self) self.listView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.listView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) self.listView.setMinimumWidth(200) self.listView.setMaximumWidth(400) self.listView.setFont(globalFont) self.textEdit = QTextEdit(self) self.textEdit.setMinimumWidth(400) self.textEdit.setFont(globalFont) self.textEdit.setLineWrapMode(QTextEdit.NoWrap) self.editLayout = QGridLayout() self.editLayout.addWidget(self.serverLabel, 0, 0, Qt.AlignLeft) self.editLayout.addWidget(self.serverLineEdit, 0, 1) self.editLayout.addWidget(self.userLabel, 0, 2, Qt.AlignLeft) self.editLayout.addWidget(self.userLineEdit, 0, 3) self.editLayout.addWidget(self.passwdLabel, 0, 4, Qt.AlignLeft) self.editLayout.addWidget(self.passwdLineEdit, 0, 5) self.gridLayout = QGridLayout() self.gridLayout.addLayout(self.editLayout, 0, 0, 1, 2) self.gridLayout.addWidget(self.listView, 1, 0, Qt.AlignLeft) self.gridLayout.addWidget(self.textEdit, 1, 1, Qt.AlignLeft) self.gridLayout.addWidget(self.connectButton, 2, 0, Qt.AlignLeft) self.gridLayout.addWidget(self.quitButton, 2, 1, Qt.AlignRight) self.mainWidget = QWidget(self) self.mainWidget.setLayout(self.gridLayout) self.setCentralWidget(self.mainWidget) def center(self): screen = QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)
class CompileWidget(QWidget): progress = pyqtSignal(int) def __init__(self, parent=None): QWidget.__init__(self, parent) self._options = None self._conf = None self._go = QPushButton('Go') self._go.setMaximumWidth(100) font = self._go.font() font.setPointSizeF(font.pointSizeF() * 2.0) font.setWeight(QFont.Bold) self._go.setFont(font) self._go.clicked.connect(self.go) self._saveLog = QPushButton('Save') saveLogLabel = QLabel('Log File:') saveLogBrowse = QPushButton('&Browse') saveLogBrowse.clicked.connect(self.browseSaveLog) self._saveLogEdit = QLineEdit('') gLayout = QGridLayout() gLayout.addWidget(saveLogLabel, 0, 0, 1, 1, Qt.AlignRight) gLayout.addWidget(self._saveLogEdit, 0, 1, 1, 6) gLayout.addWidget(saveLogBrowse, 0, 7, 1, 1) self._console = QTextEdit() self._console.setLineWrapMode(QTextEdit.NoWrap) self._console.setMinimumSize(800, 400) palette = self._console.palette() palette.setColor(QPalette.Base, QColor.fromRgb(255, 255, 221)) # ffffdd. self._console.setPalette(palette) font = QFont('Bitstream Vera Sans Mono', self._console.font().pointSize()) self._console.setFont(font) self._highlighter = Highlighter(self._console.document()) self._progressBar = QProgressBar() self._progressBar.setRange(0, 100) self._progressBar.setTextVisible(True) hLayout = QHBoxLayout() hLayout.addStretch() hLayout.addWidget(self._go) hLayout.addStretch() hLayout.addWidget(self._saveLog) hLayout.addStretch() vLayout = QVBoxLayout() vLayout.addLayout(hLayout) vLayout.addLayout(gLayout) vLayout.addWidget(self._progressBar) vLayout.addWidget(self._console) self.setLayout(vLayout) self.progress.connect(self._progressBar.setValue) self._saveLog.clicked.connect(self.saveLog) self.readSettings() return def _setOptions(self, options): self._options = options def _setConf(self, conf): self._conf = conf def _getOptions(self): return self._options def _getConf(self): return self._conf options = property(_getOptions, _setOptions) conf = property(_getConf, _setConf) def browseSaveLog(self): self._saveLogEdit.setText( QFileDialog.getSaveFileName(self, 'Select Log File Report', self._saveLogEdit.text(), 'Report Files (*.log *.txt)')) return def saveLog(self): if self._saveLogEdit.text(): fd = open(self._saveLogEdit.text(), 'w+') fd.write(self._console.toPlainText()) fd.close() return def shellCommand(self): command = [self.conf.bootstrapDir + '/ccb.py'] for project in self.options.projects: for tool in project.actives: command += ['--tool=' + tool] toolsCount = len(command) - 1 if self.conf.rootDir: command += ['--root=%s' % self.conf.rootDir] #if self.options.svnUpdate: command += [ '--svn-update' ] #if self.options.svnStatus: command += [ '--svn-update' ] if self.options.enableDoc: command += ['--doc'] if self.options.devtoolset2: command += ['--devtoolset-2'] if self.options.qt5: command += ['--qt5'] if self.options.noCache: command += ['--no-cache'] if self.options.rmBuild: command += ['--rm-build'] if self.options.verbose: command += ['--verbose'] if self.options.make: makeArguments = 'install ' + self.options.threads command += ['--make=%s' % makeArguments] if self.options.buildMode == 'Debug': command += ['--debug'] return toolsCount, command def go(self): rePercentage = re.compile(r'^\[\s*(?P<percent>\d+)%\].*') reProcessTool = re.compile(r'^Processing tool:\s*"(?P<tool>.+)"') if not self.options or not self.conf: return toolsCount, command = self.shellCommand() if not toolsCount: return self._progressBar.reset() self._progressBar.setRange(0, toolsCount * 100) strCommand = command[0] for arg in command[1:]: strCommand += ' ' + arg strCommand += '\n\n' self._console.setFontItalic(True) self._console.insertPlainText(strCommand) self._console.setFontItalic(False) toolsDone = -1 builderProcess = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) while True: line = builderProcess.stdout.readline() if line == '': break m = rePercentage.match(line) if m: self.progress.emit(toolsDone * 100 + int(m.group('percent'))) else: m = reProcessTool.match(line) if m: toolsDone += 1 self._console.insertPlainText(line) scrollBar = self._console.verticalScrollBar() scrollBar.setValue(scrollBar.maximum()) QApplication.processEvents() builderProcess.wait() if builderProcess.returncode == None: pass return def readSettings(self): settings = QSettings() self._saveLogEdit.setText(settings.value('compile/saveLog').toString()) return def saveSettings(self): settings = QSettings() settings.setValue('compile/saveLog', self._saveLogEdit.text()) return
class LineTextWidget(QFrame): class NumberBar(QWidget): def __init__(self, *args): QWidget.__init__(self, *args) self.edit = None # This is used to update the width of the control. # It is the highest line that is currently visibile. self.highest_line = 0 def setTextEdit(self, edit): self.edit = edit def update(self, *args): ''' Updates the number bar to display the current set of numbers. Also, adjusts the width of the number bar if necessary. ''' # The + 4 is used to compensate for the current line being bold. width = self.fontMetrics().width(str(self.highest_line)) + 4 if self.width() != width: self.setFixedWidth(width) QWidget.update(self, *args) def paintEvent(self, event): contents_y = self.edit.verticalScrollBar().value() page_bottom = contents_y + self.edit.viewport().height() font_metrics = self.fontMetrics() current_block = self.edit.document().findBlock(self.edit.textCursor().position()) painter = QPainter(self) line_count = 0 # Iterate over all text blocks in the document. block = self.edit.document().begin() while block.isValid(): line_count += 1 # The top left position of the block in the document position = self.edit.document().documentLayout().blockBoundingRect(block).topLeft() # Check if the position of the block is out side of the visible # area. if position.y() > page_bottom: break # We want the line number for the selected line to be bold. bold = False if block == current_block: bold = True font = painter.font() font.setBold(True) painter.setFont(font) # Draw the line number right justified at the y position of the # line. 3 is a magic padding number. drawText(x, y, text). painter.drawText(self.width() - font_metrics.width(str(line_count)) - 3, round(position.y()) - contents_y + font_metrics.ascent(), str(line_count)) # Remove the bold style if it was set previously. if bold: font = painter.font() font.setBold(False) painter.setFont(font) block = block.next() self.highest_line = line_count painter.end() QWidget.paintEvent(self, event) def __init__(self, *args): QFrame.__init__(self, *args) #self.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) self.edit = QTextEdit(*args) #self.edit.setFrameStyle(QFrame.NoFrame) self.edit.setLineWrapMode(QTextEdit.NoWrap) self.edit.setAcceptRichText(False) #self.edit.setReadOnly(True) self.number_bar = self.NumberBar() self.number_bar.setTextEdit(self.edit) hbox = QHBoxLayout(self) hbox.setSpacing(0) hbox.setMargin(0) hbox.addWidget(self.number_bar) hbox.addWidget(self.edit) self.edit.installEventFilter(self) self.edit.viewport().installEventFilter(self) def setText(self, text): self.edit.setText(text) def toPlainText(self): return self.edit.toPlainText() def setFocus(self): self.edit.setFocus() def append(self, text): self.edit.append(text) def eventFilter(self, object, event): # Update the line numbers for all events on the text edit and the viewport. # This is easier than connecting all necessary singals. if object in (self.edit, self.edit.viewport()): self.number_bar.update() return False return QFrame.eventFilter(object, event) def getTextEdit(self): return self.edit
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self._create_components() self._place_components() self._create_controller() self.setWindowTitle("Job Crawler") def _create_components(self): self.site_gb = QGroupBox(u"Choix des sites") self.param_gb = QGroupBox(u"Autres Paramètres") self.search_gb = QGroupBox(u"Mots-clé") self.log_gb = QGroupBox(u"Logs") self.apec_cb = QCheckBox(u"APEC") self.apec_cb.setDisabled(True) self.caoe_cb = QCheckBox(u"CAO Emploi") self.caoe_cb.setDisabled(True) self.inde_cb = QCheckBox(u"Indeed") self.mons_cb = QCheckBox(u"Monster Job") self.mons_cb.setDisabled(True) self.pole_cb = QCheckBox(u"Pole Enmploi") self.pole_cb.setDisabled(True) self.regi_cb = QCheckBox(u"Région Job") self.regi_cb.setDisabled(True) self.search_label = QLabel(u"Mots-clé de recherche") self.filter_label = QLabel(u"Critère de filtrage") self.region_label = QLabel(u"Région") self.daterange_label = QLabel(u"Plage de recherche") self.search_qle = QLineEdit() self.filter_qle = QLineEdit() self.start_button = QPushButton(u"Rechercher") self.stop_button = QPushButton(u"Stopper") self.stop_button.setDisabled(True) self.daterange_sb = QSpinBox() self.daterange_sb.setMaximum(40) self.daterange_sb.setProperty("value", 3) self.daterange_sb.setSuffix(u" Jours") self.region_cb = QComboBox() region_list = toolbox.getconfigvalue("STATIC", "regions").split(',') self.region_cb.addItems(region_list) self.log_te = QTextEdit() self.log_te.setReadOnly(True) self.log_te.setLineWrapMode(QTextEdit.NoWrap) self.file_menu = QMenu(u"Fichier") self.help_menu = QMenu(u"Aide") def _place_components(self): site_layout = QHBoxLayout() temp = QVBoxLayout() temp.addWidget(self.apec_cb) temp.addWidget(self.caoe_cb) temp.addWidget(self.inde_cb) site_layout.addLayout(temp) temp = QVBoxLayout() temp.addWidget(self.mons_cb) temp.addWidget(self.pole_cb) temp.addWidget(self.regi_cb) site_layout.addLayout(temp) self.site_gb.setLayout(site_layout) search_layout = QVBoxLayout() search_layout.addWidget(self.search_label) search_layout.addWidget(self.search_qle) search_layout.addWidget(self.filter_label) search_layout.addWidget(self.filter_qle) self.search_gb.setLayout(search_layout) param_layout = QVBoxLayout() param_layout.addWidget(self.daterange_label) param_layout.addWidget(self.daterange_sb) param_layout.addWidget(self.region_label) param_layout.addWidget(self.region_cb) self.param_gb.setLayout(param_layout) log_layout = QVBoxLayout() log_layout.addWidget(self.log_te) self.log_gb.setLayout(log_layout) command_layout = QHBoxLayout() command_layout.addWidget(self.start_button) command_layout.addWidget(self.stop_button) main_layout = QVBoxLayout() main_layout.addWidget(self.site_gb) main_layout.addWidget(self.search_gb) main_layout.addWidget(self.param_gb) main_layout.addWidget(self.log_gb) main_layout.addLayout(command_layout) centralwidget = QWidget(self) centralwidget.setLayout(main_layout) self.setCentralWidget(centralwidget) menubar = self.menuBar() menubar.addMenu(self.file_menu) menubar.addMenu(self.help_menu) def _create_controller(self): adminAction = QAction(u'Administration', self) adminAction.setStatusTip(u'Régler les paramètres de l\'application') adminAction.triggered.connect(self.admin) exitAction = QAction(u'Quitter', self) exitAction.setStatusTip(u'Quitter Job Crawler') exitAction.triggered.connect(qApp.quit) aboutAction = QAction(u'A propos', self) aboutAction.setStatusTip(u'Afficher la fenêtre à propos') aboutAction.triggered.connect(self.about) self.file_menu.addAction(adminAction) self.file_menu.addSeparator() self.file_menu.addAction(exitAction) self.help_menu.addAction(aboutAction) self.start_button.clicked.connect(self.start) self.stop_button.clicked.connect(self.stop) # Controller for logging XStream.stdout().messageWritten.connect( self.log_te.insertPlainText ) XStream.stderr().messageWritten.connect( self.log_te.insertPlainText ) def validate_fields(self): error = False error_list = u"" inde = self.inde_cb.isChecked() apec = self.apec_cb.isChecked() caoe = self.caoe_cb.isChecked() mons = self.mons_cb.isChecked() pole = self.pole_cb.isChecked() regi = self.regi_cb.isChecked() if not (inde or apec or caoe or mons or pole or regi): error = True error_list += u"<li>Site à requêter</li>" searchkeyword = unidecode(unicode(self.search_qle.text())) if searchkeyword == u"": error = True error_list += u"<li>Mots clé de recherche</li>" filterkeyword = unidecode(unicode(self.filter_qle.text())) if filterkeyword == u"": error = True error_list += u"<li>Critère de filtrage</li>" if error: message = u"Veuillez renseigner le(s) champ(s) suivant(s) :<ul>" + error_list + u"</ul>" QMessageBox.warning(self, u"Erreur", message) return not error def validate_admin(self): dbpath = toolbox.getconfigvalue("GENERAL", "dbfile") if not (dbpath != "" and os.access(os.path.dirname(dbpath), os.W_OK)): message = u"<p>Veuiller renseigner l'emplacement de la base de données dans l'administration (Fichier > Administration).</p>"\ u"<p>Si cela a déjà été fait, ce message signifie que vous n'avez pas les droits d'écriture dans ce répertoire. Veuillez déplacer la base de données et reconfigurer l'emplacement dans l'administration.</p>" QMessageBox.warning(self, u"Erreur", message) return False return True @pyqtSlot() def start(self): def run(): self.start_button.setDisabled(True) # self.stop_button.setEnabled(True) logger.info(u"Début") inde = self.inde_cb.isChecked() apec = self.apec_cb.isChecked() caoe = self.caoe_cb.isChecked() mons = self.mons_cb.isChecked() pole = self.pole_cb.isChecked() regi = self.regi_cb.isChecked() searchkeyword = unidecode(unicode(self.search_qle.text())).split(",") filterkeyword = unidecode(unicode(self.filter_qle.text())).split(",") daterange = self.daterange_sb.value() region = str(self.region_cb.currentText()) dbpath = toolbox.getconfigvalue("GENERAL", "dbfile") excludelist = unidecode(toolbox.getconfigvalue("GENERAL", "excludes")).split(",") c = core.core(dbpath) logger.info(u"Recherche d'annonces") c.found_annonce(searchkeyword, daterange, region, None, apec, caoe, inde, mons, pole, regi) logger.info(u"Tri des annonces par rapport aux mots-clé d'exclusion") c.exclude_annouces(excludelist) logger.info(u"Tri des annonces par rapport aux critères de filtrage") c.filter_announces(filterkeyword) logger.info(u"Fin") # self.stop_button.setDisabled(True) self.start_button.setEnabled(True) if self.validate_fields() and self.validate_admin(): self.thread = threading.Thread(target=run) self.thread.start() @pyqtSlot() def stop(self): self.thread._Thread__stop() self.stop_button.setDisabled(True) self.start_button.setEnabled(True) @pyqtSlot() def about(self): self.aboutwindow = aboutdialog.AboutDialog(self).exec_() @pyqtSlot() def admin(self): admindialog.AdminDialog(self).exec_()
class SimpleViewWidget(QWidget): # http://www.colourlovers.com/palette/1930/cheer_up_emo_kid colors = ["C44D58", "C7F464", "4ECDC4", "556270", "FF6B6B"] def __init__(self, parent, logger): super(SimpleViewWidget, self).__init__(parent) self.logger = logger self.colorMap = {} self.colorCounter = 0 layout = QVBoxLayout(self) self.memberView = QLabel(self) self.memberView.setAlignment(Qt.AlignHCenter) self.addMemberWidget = QWidget(self) addMemberLayout = QHBoxLayout(self.addMemberWidget) addMemberLayout.setContentsMargins(0, 0, 0, 0) addMemberLayout.addWidget(QLabel(u"Add Member", self), 0) self.addMemberEdit = QLineEdit(self) if hasattr(self.addMemberEdit, "setPlaceholderText"): self.addMemberEdit.setPlaceholderText(u"IP or Hostname") self.addMemberEdit.returnPressed.connect(self._addMember) addMemberLayout.addWidget(self.addMemberEdit, 1) addMemberButton = QPushButton("Add", self) addMemberButton.clicked.connect(self._addMember) addMemberLayout.addWidget(addMemberButton, 0) sendLayout = QHBoxLayout() sendMessageField = QLineEdit(self) if hasattr(sendMessageField, "setPlaceholderText"): sendMessageField.setPlaceholderText("optional Message") lunchButton = LunchButton(parent, sendMessageField) sendLayout.addWidget(sendMessageField) sendLayout.addWidget(lunchButton) self.msgview = QTextEdit(self) self.msgview.setLineWrapMode(QTextEdit.WidgetWidth) self.msgview.setReadOnly(True) layout.addWidget(self.addMemberWidget) layout.addWidget(self.memberView) layout.addLayout(sendLayout) layout.addWidget(self.msgview) get_notification_center().connectMemberAppended(self._memberAppended) get_notification_center().connectMemberAppended(self.updateWidgets) get_notification_center().connectMemberUpdated(self.updateWidgets) get_notification_center().connectMemberRemoved(self.updateWidgets) get_notification_center().connectMessagePrepended(self.updateWidgets) self.timer = QTimer(self) self.timer.timeout.connect(self.updateWidgets) self.timer.start(60000) def showEvent(self, showEvent): self.updateWidgets() @loggingSlot() def _addMember(self): hostn = convert_raw(self.addMemberEdit.text()) if hostn: get_server().call_request_info([hostn]) def getMemberColor(self, peerID): if not self.colorMap.has_key(peerID): self.colorMap[peerID] = self.colors[self.colorCounter] self.colorCounter = (self.colorCounter + 1) % len(self.colors) return self.colorMap[peerID] @loggingSlot(object, object) def _memberAppended(self, pID, _infoDict): if not get_peers().isMe(pID=pID): self.addMemberWidget.setVisible(False) @pyqtSlot(struct_time, object, object) @pyqtSlot(object, object) @pyqtSlot(object) @loggingSlot() def updateWidgets(self, _=None, __=None, ___=None): if not self.isVisible(): return True peers = get_peers() if peers is not None: members = peers.getMembers() readyMembers = peers.getReadyMembers() notReadyMembers = peers.getMembers() - readyMembers else: members = [] readyMembers = [] notReadyMembers = [] memText = "%d group members online<br />" % len(members) memToolTip = "" # don't display members with unknown status as ready readyMembers = [pID for pID in readyMembers if peers.isPeerReadinessKnown(pID=pID)] readyText = ", ".join([peers.getDisplayedPeerName(pID=x) for x in readyMembers]) notReadyText = ", ".join([peers.getDisplayedPeerName(pID=x) for x in notReadyMembers]) memToolTip += "<span style='color:green'>%s</span><br />" % readyText if len(readyMembers) else "" memToolTip += "<span style='color:red'>%s</span>" % notReadyText if len(notReadyMembers) else "" memText += "<span style='color:green'>%d ready for lunch</span>" % len(readyMembers) if len(readyMembers) else "no one ready for lunch" self.memberView.setText(memText) self.memberView.setToolTip(memToolTip) msgTexts = "" with get_server().get_messages(): messages = get_server().get_messages().getAll(time() - (180 * 60)) for timest, peerID, msg in messages: member = peers.getDisplayedPeerName(pID=peerID) color = self.getMemberColor(peerID) msgTexts += "<span style='color:#%s'><b>%s</b> \ <i>[%s]</i>: %s</span><br />\n" % (color, member,strftime("%H:%M",timest), msg) self.msgview.setHtml(msgTexts) def create_menu(self, menuBar): windowMenu = QMenu("Advanced", menuBar) windowMenu.addAction("Manually add an IP", self.addMemberByIP) return windowMenu def addMemberByIP(self): hostn, button = QInputDialog.getText(None, "Manually add a member", "In rare cases the lunchinator might not be available to find another user.\n" + "You can enter an IP/hostname here to explicitly look there. Make sure that the Lunchinator is running on\n" + "the other machine and that you are in the same group.") if button and len(hostn): get_server().call_request_info([str(hostn)]) def finish(self): try: self.timer.timeout.disconnect() get_notification_center().disconnectMemberAppended(self.updateWidgets) get_notification_center().disconnectMemberUpdated(self.updateWidgets) get_notification_center().disconnectMemberRemoved(self.updateWidgets) get_notification_center().disconnectMessagePrepended(self.updateWidgets) except: self.logger.info("Simple View: was not able to disconnect timer")
class LineTextWidget(QFrame): class NumberBar(QWidget): def __init__(self, *args): QWidget.__init__(self, *args) self.edit = None # This is used to update the width of the control. # It is the highest line that is currently visibile. self.highest_line = 0 def setTextEdit(self, edit): self.edit = edit def update(self, *args): ''' Updates the number bar to display the current set of numbers. Also, adjusts the width of the number bar if necessary. ''' # The + 4 is used to compensate for the current line being bold. width = self.fontMetrics().width(str(self.highest_line)) + 4 if self.width() != width: self.setFixedWidth(width) QWidget.update(self, *args) def paintEvent(self, event): contents_y = self.edit.verticalScrollBar().value() page_bottom = contents_y + self.edit.viewport().height() font_metrics = self.fontMetrics() current_block = self.edit.document().findBlock( self.edit.textCursor().position()) painter = QPainter(self) line_count = 0 # Iterate over all text blocks in the document. block = self.edit.document().begin() while block.isValid(): line_count += 1 # The top left position of the block in the document position = self.edit.document().documentLayout( ).blockBoundingRect(block).topLeft() # Check if the position of the block is out side of the visible # area. if position.y() > page_bottom: break # We want the line number for the selected line to be bold. bold = False if block == current_block: bold = True font = painter.font() font.setBold(True) painter.setFont(font) # Draw the line number right justified at the y position of the # line. 3 is a magic padding number. drawText(x, y, text). painter.drawText( self.width() - font_metrics.width(str(line_count)) - 3, round(position.y()) - contents_y + font_metrics.ascent(), str(line_count)) # Remove the bold style if it was set previously. if bold: font = painter.font() font.setBold(False) painter.setFont(font) block = block.next() self.highest_line = line_count painter.end() QWidget.paintEvent(self, event) def __init__(self, *args): QFrame.__init__(self, *args) #self.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) self.edit = QTextEdit(*args) #self.edit.setFrameStyle(QFrame.NoFrame) self.edit.setLineWrapMode(QTextEdit.NoWrap) self.edit.setAcceptRichText(False) #self.edit.setReadOnly(True) self.number_bar = self.NumberBar() self.number_bar.setTextEdit(self.edit) hbox = QHBoxLayout(self) hbox.setSpacing(0) hbox.setMargin(0) hbox.addWidget(self.number_bar) hbox.addWidget(self.edit) self.edit.installEventFilter(self) self.edit.viewport().installEventFilter(self) def setText(self, text): self.edit.setText(text) def toPlainText(self): return self.edit.toPlainText() def setFocus(self): self.edit.setFocus() def append(self, text): self.edit.append(text) def eventFilter(self, object, event): # Update the line numbers for all events on the text edit and the viewport. # This is easier than connecting all necessary singals. if object in (self.edit, self.edit.viewport()): self.number_bar.update() return False return QFrame.eventFilter(object, event) def getTextEdit(self): return self.edit
class DownloaderWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.DownloadPath = os.path.expanduser("~") # get home dir self.pool = QThreadPool() self.pool.setMaxThreadCount(1) self.initVariables() self.resize(700, 400) self.initUI() self.line_downpath.setText(self.down_control.getDownloadPath()) def initVariables(self): self.down_control = DownloadController(self.addInfo) self.down_control.setDownloadPath(self.DownloadPath) self.chapters = None self.chapters_filtered = None self.ch_from = None self.ch_to = None def initUI(self): cw = QWidget() self.setCentralWidget(cw) layout_main = QVBoxLayout() layout_main.setSpacing(5) ## Info self.info = QTextEdit() self.info.setReadOnly(True) self.info.setLineWrapMode(QTextEdit.NoWrap) layout_main.addWidget(self.info, 1) ## Line edit layout_url = QHBoxLayout() layout_url.setSpacing(5) self.line_url = QLineEdit() layout_url.addWidget(QLabel('<b>Series URL:</b>')) layout_url.addWidget(self.line_url, 1) layout_main.addLayout(layout_url) ## Comboboxes layout_combo = QHBoxLayout() layout_combo.setSpacing(5) self.combo_from = QComboBox() self.combo_from.setEnabled(False) self.combo_to = QComboBox() self.combo_to.setEnabled(False) layout_combo.addWidget(QLabel('<b>Download chapters: </b>')) layout_combo.addWidget(QLabel(' From:')) layout_combo.addWidget(self.combo_from, 1) layout_combo.addWidget(QLabel('To:')) layout_combo.addWidget(self.combo_to, 1) layout_main.addLayout(layout_combo) ## Download path layout_downpath = QHBoxLayout() layout_downpath.setSpacing(5) self.line_downpath = QLineEdit() self.line_downpath.setEnabled(False) self.btn_downpath = QPushButton('Change') self.btn_downpath.pressed.connect(self.selectDownloadPath) layout_downpath.addWidget(QLabel('<b>Download path:</b>')) layout_downpath.addWidget(self.line_downpath, 1) layout_downpath.addWidget(self.btn_downpath) layout_main.addLayout(layout_downpath) ## Buttons layout_btn = QHBoxLayout() layout_btn.setSpacing(5) self.btn_getlist = QPushButton('Get List of Chapters') self.btn_getlist.pressed.connect(self.getChaptersList) self.btn_download = QPushButton('Download chapters') self.btn_download.pressed.connect(self.downloadChapters) self.btn_download.setEnabled(False) self.btn_exit = QPushButton('Exit') self.btn_exit.pressed.connect(self.close) layout_btn.addStretch() layout_btn.addWidget(self.btn_getlist) layout_btn.addWidget(self.btn_download) layout_btn.addWidget(self.btn_exit) layout_btn.addStretch() layout_main.addLayout(layout_btn) # status bar self.statusBar().showMessage('Ready') # add layout to main window cw.setLayout(layout_main) self.setWindowTitle('OMAD - Online MAnga Downloader') self.show() def closeEvent(self, event): """ Runs when user tryes to close main window. sys.exit(0) - to fix wierd bug, where process is not terminated. """ sys.exit(0) def addInfo(self, s='Testing printing...', exception=False, downloadProgress=False, trace=[]): logger.info(s+', '+str(exception)+', '+str(downloadProgress)+', '+str(trace)) if type(s)!=type("") and type(s)!=type(b"") and type(s) != type(QtCore.QString('')): s = str(s) if exception: s = "!!! Exception: "+s if downloadProgress: s = "Downloading progress: "+s self.setStatusBarText(s) self.info.append(s) if exception: for t in trace: self.info.append(str(t)) sb = self.info.verticalScrollBar() sb.setValue(sb.maximum()) QtCore.QCoreApplication.processEvents() def setStatusBarText(self, s='Testing...'): """ Changes status bar text """ self.statusBar().showMessage(s) QtCore.QCoreApplication.processEvents() def getChaptersList(self): self.addInfo('Getting list of chapters...') # reinit clean variables self.initVariables() # get series url url = str(self.line_url.text()).strip() if not self.down_control.setSeriesUrl(url): return # bad url self.chapters = self.down_control.getChaptersList() logger.debug('Setting up comboBoxes...') for i in range(0, self.combo_from.count()): self.combo_from.removeItem(0) for i in range(0, self.combo_to.count()): self.combo_to.removeItem(0) for c in self.chapters: self.combo_from.addItem(c[0]) self.combo_to.addItem(c[0]) self.combo_from.setCurrentIndex(0) self.combo_to.setCurrentIndex(len(self.chapters)-1) self.addInfo('Chapter list loaded') self.combo_from.setEnabled(True) self.combo_to.setEnabled(True) self.btn_download.setEnabled(True) def downloadChapters(self): self.addInfo('Checking chapter range') self.ch_from = self.combo_from.currentIndex() self.ch_to = self.combo_to.currentIndex() if self.ch_from>self.ch_to: self.addInfo('Bad range. Cant download backwards!') return else: self.addInfo('Range OK, starting download of '+str((self.ch_to-self.ch_from)+1)+' chapters...') self.gui_disable(True) worker = DownloadWorker(self.down_control, self.ch_from, self.ch_to) worker.signals.update.connect(self.addInfo) worker.signals.finished.connect(self.downloadChapters_finished) self.pool.start(worker) def downloadChapters_finished(self): self.gui_disable(False) self.setStatusBarText('Ready - Download Finished!!') # Finished self.addInfo('Download Finished!!') # Print failed downloads failed_chs = [] for i, r in enumerate(self.down_control.results): if r is False: failed_chs.append(self.chapters[i+self.ch_from]) if len(failed_chs)==0: self.addInfo('\nNo failed downloads') else: self.addInfo('\nChapters with failed downloads:') for c in failed_chs: self.addInfo(c[0]) self.addInfo('') def selectDownloadPath(self): downdir = self._get_dir(directory=self.DownloadPath) self.down_control.setDownloadPath(downdir) self.DownloadPath = self.down_control.getDownloadPath() self.line_downpath.setText(self.DownloadPath) def _get_dir(self, directory=''): """ Draw a dialog for directory selection. """ downdir = QFileDialog.getExistingDirectory( caption='Select Folder', options=QFileDialog.ShowDirsOnly, directory=directory ) if len(downdir) > 0: downdir = "%s" % (downdir) else: downdir = directory return downdir def gui_disable(self, downloading=True): self.line_url.setEnabled(not downloading) self.combo_from.setEnabled(not downloading) self.combo_to.setEnabled(not downloading) self.btn_getlist.setEnabled(not downloading) self.btn_download.setEnabled(not downloading) self.btn_downpath.setEnabled(not downloading)
class BugReportsWidget(QWidget): PREFERRED_WIDTH = 400 PREFERRED_HEIGHT = 150 def __init__(self, parent, mt): super(BugReportsWidget, self).__init__(parent) self.mt = mt layout = QVBoxLayout(self) # layout.setContentsMargins(0, 0, 0, 0) self.entry = QTextEdit(self) self.issues = {} self.issuesComboModel = IssuesComboModel() self.dropdown_reports = QComboBox(self) self.dropdown_reports.setModel(self.issuesComboModel) self.display_report() self.details_btn = QPushButton("Details", self) self.details_btn.setEnabled(False) self.refresh_btn = QPushButton("Refresh", self) create_report_btn = QPushButton("New", self) topLayout = QHBoxLayout() topLayout.addWidget(self.dropdown_reports, 1) topLayout.addWidget(self.details_btn) topLayout.addWidget(self.refresh_btn) topLayout.addSpacing(20) topLayout.addWidget(create_report_btn) layout.addLayout(topLayout) layout.addWidget(QLabel("Description:", self)) self.entry.setLineWrapMode(QTextEdit.WidgetWidth) self.entry.setReadOnly(True) layout.addWidget(self.entry) self.dropdown_reports.currentIndexChanged.connect(self.display_report) self.details_btn.clicked.connect(self.displayReportDetails) self.refresh_btn.clicked.connect(self.update_reports) create_report_btn.clicked.connect(self.createBugReport) self.update_reports() def repoChanged(self): self.update_reports() def displayReportDetails(self): selectedIssue = self.selectedIssue() if selectedIssue == None: return url = selectedIssue.issueUrl if url != None: webbrowser.open(url, new=2) def isRepoSpecified(self): repoUser = self.mt.options[u"repo_user"] repoName = self.mt.options[u"repo_name"] if repoUser and repoName: return True return False @pyqtSlot(QThread, unicode) def downloadedIssues(self, thread, _): self.refresh_btn.setEnabled(self.isRepoSpecified()) j = json.loads(thread.getResult()) newKeys = set() for i, issueDict in enumerate(j): issue = Issue(issueDict) newKeys.add(issue.id) self.issues[issue.id] = issue if not self.issuesComboModel.hasKey(issue.id): self.issuesComboModel.externalRowInserted(issue.id, issue, i) else: self.issuesComboModel.externalRowUpdated(issue.id, issue) oldKeys = set(self.issuesComboModel.keys) for removedKey in oldKeys - newKeys: self.issuesComboModel.externalRowRemoved(removedKey) self.details_btn.setEnabled(self.issuesComboModel.rowCount() > 0) @pyqtSlot(QThread, unicode) def errorDownloadingIssues(self, _thread, _url): self.refresh_btn.setEnabled(self.isRepoSpecified()) log_error("Error fetching issues from github.") def update_reports(self): self.refresh_btn.setEnabled(False) repoUser = self.mt.options[u"repo_user"] repoName = self.mt.options[u"repo_name"] if repoUser and repoName: log_debug("Fetching issues from repository %s/%s" % (repoUser, repoName)) thread = DownloadThread(self, "https://api.github.com/repos/%s/%s/issues?state=open" % (repoUser, repoName)) thread.finished.connect(thread.deleteLater) thread.error.connect(self.errorDownloadingIssues) thread.success.connect(self.downloadedIssues) thread.start() else: log_warning("No Lunchinator GitHub repository specified.") def createBugReport(self): repoUser = self.mt.options[u"repo_user"] repoName = self.mt.options[u"repo_name"] if repoUser and repoName: url = "https://github.com/%s/%s/issues/new" % (repoUser, repoName) if url != None: webbrowser.open(url, new=2) else: log_warning("No Lunchinator GitHub repository specified.") QMessageBox.critical(self, "No Repository", "No Lunchinator GitHub repository specified.", buttons=QMessageBox.Ok, defaultButton=QMessageBox.Ok) def selectedIssue(self): issueID = self.dropdown_reports.itemData(self.dropdown_reports.currentIndex(), IssuesComboModel.KEY_ROLE).toInt()[0] if not issueID in self.issues: log_error("ID of selected issue is not in issues dictionary") return None return self.issues[issueID] def display_report(self): if self.dropdown_reports.currentIndex()>=0: self.entry.setText(self.selectedIssue().description) def sizeHint(self): return QSize(self.PREFERRED_WIDTH, self.PREFERRED_HEIGHT)
class MembersWidget(QWidget): def __init__(self, parent, logger): super(MembersWidget, self).__init__(parent) self.logger = logger layout = QVBoxLayout(self) layout.setSpacing(0) self.dropdown_members_dict = {} self.dropdown_members_model = DropdownModel(get_peers(), self.logger) self.dropdown_members = QComboBox(self) self.dropdown_members.setModel(self.dropdown_members_model) topLayout = QHBoxLayout() topLayout.setSpacing(10) topLayout.addWidget(self.dropdown_members, 1) self.requestLogsButton = QPushButton("Request Logfiles", self) topLayout.addWidget(self.requestLogsButton) layout.addLayout(topLayout) layout.addWidget(QLabel("Member Information:", self)) self.memberInformationTable = QTreeWidget(self) self.memberInformationTable.setMaximumHeight(65) self.memberInformationTable.setSelectionMode(QTreeWidget.NoSelection) layout.addWidget(self.memberInformationTable, 0) layout.addWidget(QLabel("Send Message:", self)) sendMessageLayout = QHBoxLayout() sendMessageLayout.setSpacing(10) messageInput = HistoryLineEdit(self, "Enter a message") self.sendMessageButton = QPushButton("Send", self) sendMessageLayout.addWidget(messageInput, 1) sendMessageLayout.addWidget(self.sendMessageButton) layout.addLayout(sendMessageLayout) layout.addWidget(QLabel("Log files:", self)) logSplitter = QSplitter(Qt.Horizontal, self) logListWidget = QWidget(self) logListLayout = QVBoxLayout(logListWidget) logListLayout.setContentsMargins(0, 0, 0, 0) self.log_tree_view = QTreeWidget(logSplitter) self.log_tree_view.setAlternatingRowColors(True) self.log_tree_view.setColumnCount(1) self.log_tree_view.setHeaderHidden(True) self.log_tree_view.setItemsExpandable(False) self.log_tree_view.setIndentation(0) logListLayout.addWidget(self.log_tree_view, 1) logListBottomLayout = QHBoxLayout() self.logSizeLabel = QLabel(logListWidget) logListBottomLayout.addWidget(self.logSizeLabel, 1) self.clearLogsButton = QPushButton("Clear", logListWidget) self.clearLogsButton.setEnabled(False) self.clearLogsButton.clicked.connect(self.clearLogs) logListBottomLayout.addWidget(self.clearLogsButton, 0) logListLayout.addLayout(logListBottomLayout) logSplitter.addWidget(logListWidget) self.log_area = QTextEdit(logListWidget) self.log_area.setLineWrapMode(QTextEdit.WidgetWidth) self.log_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.log_area.setReadOnly(True) logSplitter.addWidget(self.log_area) logSplitter.setStretchFactor(0, 0) logSplitter.setStretchFactor(1, 1) layout.addWidget(logSplitter, 1) self.memberSelectionChanged() self.log_tree_view.selectionModel().selectionChanged.connect(self.displaySelectedLogfile) self.dropdown_members.currentIndexChanged.connect(self.memberSelectionChanged) self.requestLogsButton.clicked.connect(self.requestLogClicked) self.sendMessageButton.clicked.connect(partial(self.sendMessageToMember, messageInput)) messageInput.returnPressed.connect(partial(self.sendMessageToMember, messageInput)) get_notification_center().connectPeerAppended(self.dropdown_members_model.externalRowAppended) get_notification_center().connectPeerUpdated(self.dropdown_members_model.externalRowUpdated) get_notification_center().connectPeerRemoved(self.dropdown_members_model.externalRowRemoved) get_notification_center().connectPeerUpdated(self.updateMemberInformation) def destroy_widget(self): get_notification_center().disconnectPeerAppended(self.dropdown_members_model.externalRowAppended) get_notification_center().disconnectPeerUpdated(self.dropdown_members_model.externalRowUpdated) get_notification_center().disconnectPeerRemoved(self.dropdown_members_model.externalRowRemoved) get_notification_center().disconnectPeerUpdated(self.updateMemberInformation) def listLogfiles(self, basePath, sort=None): if sort is None: sort = lambda aFile: -self.getLogNumber(aFile) logList = [ os.path.join(basePath, aFile) for aFile in os.listdir(basePath) if aFile.endswith(".log") and not os.path.isdir(os.path.join(basePath, aFile)) ] return sorted(logList, key=sort) def getNumLogsToKeep(self, oldLogFiles, newLogFiles, logOffset): oldestNew = None for aLogFile in newLogFiles: oldestNew, _ = self.getLogDates(aLogFile) if oldestNew != None: break if oldestNew == None: # new new log file contains timestamps (they are probably all empty) return len(oldLogFiles) numToKeep = 0 while numToKeep < len(oldLogFiles) - logOffset: curTime, _ = self.getLogDates(oldLogFiles[numToKeep]) if curTime == None or curTime < oldestNew: # keep empty log files numToKeep = numToKeep + 1 else: break return numToKeep def getLogDates(self, aLogFile): with codecs.open(aLogFile, "rb", "utf-8") as logContent: logLines = logContent.readlines() firstDate = None for aLine in logLines: firstDate = getLogLineTime(aLine) if firstDate != None: break lastDate = None for aLine in reversed(logLines): lastDate = getLogLineTime(aLine) if lastDate != None: break return firstDate, lastDate def getLogNumber(self, aLogFile): aLogFile = os.path.basename(aLogFile) try: return int(aLogFile[: aLogFile.rfind(".")]) except: return -1 def shiftLogFiles(self, oldLogFiles, numToKeep, shift, logOffset): renamedLogfiles = [] for index, aFile in enumerate(oldLogFiles): logNum = self.getLogNumber(aFile) if logNum < logOffset: # don't touch up-to-date logs break if index < numToKeep: newName = os.path.join(os.path.dirname(aFile), "%d.log" % (logNum + shift)) renamedLogfiles.append((len(oldLogFiles) - index - 1, aFile, newName)) os.rename(aFile, newName) else: os.remove(aFile) return renamedLogfiles def handleNewLogFiles(self, basePath, tmpPath, logOffset=0): oldLogFiles = self.listLogfiles(basePath) newLogFiles = self.listLogfiles(tmpPath) # check how many log files are actually new numToKeep = self.getNumLogsToKeep(oldLogFiles, newLogFiles, logOffset) # rename / remove old log files to make room for the new ones numNew = len(newLogFiles) - (len(oldLogFiles) - logOffset - numToKeep) renamedLogfiles = self.shiftLogFiles(oldLogFiles, numToKeep, numNew, logOffset) # move new log files addedLogfiles = [] for index, aLogFile in enumerate(reversed(newLogFiles)): shutil.move(aLogFile, basePath) if index < numNew: addedLogfiles.append((index + logOffset, os.path.join(basePath, os.path.basename(aLogFile)))) shutil.rmtree(tmpPath, True) return numNew, addedLogfiles, renamedLogfiles def requestFinished(self): self.requestLogsButton.setEnabled(True) self.dropdown_members.setEnabled(True) @loggingSlot(QThread, object) def cb_log_transfer_success(self, thread, path): path = convert_string(path) basePath = os.path.dirname(path) tmpPath = os.path.join(basePath, "tmp") if not os.path.exists(tmpPath): os.makedirs(tmpPath) logsAdded = [] if path.endswith(".tgz"): # extract received log files with contextlib.closing(tarfile.open(path, "r:gz")) as tarContent: tarContent.extractall(tmpPath) _, logsAdded, logsRenamed = self.handleNewLogFiles(basePath, tmpPath) self.requestFinished() else: # log comes from old version logNum = 0 if thread.sender in self.logRequests: logNum, requestTime = self.logRequests[thread.sender] now = datetime.now() td = now - requestTime tdSeconds = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6) / 10 ** 6 if tdSeconds > self.LOG_REQUEST_TIMEOUT: # request timed out or was finished already logNum = 0 shutil.move(path, os.path.join(tmpPath, "%d.log" % logNum)) numNew, logsAdded, logsRenamed = self.handleNewLogFiles(basePath, tmpPath, logNum) if numNew > 0 and logNum < 9: # there might be more new ones self.logRequests[thread.sender] = (logNum + 1, datetime.now()) self.logger.debug("log seems to be new, another!!!") logsAdded.append((logNum + 1, None)) self.request_log(thread.sender, logNum + 1) elif thread.sender in self.logRequests: # request finished del self.logRequests[thread.sender] self.requestFinished() else: self.requestFinished() if len(logsAdded) > 0 or len(logsRenamed) > 0: self.updateLogList(logsAdded, logsRenamed) @loggingSlot(QThread, object) def cb_log_transfer_error(self, _thread, message): if not self.isVisible(): return False self.log_area.setText("Error while getting log (%s)" % message) self.requestFinished() def get_selected_log_member(self): member = convert_string(self.dropdown_members.currentText()) if not member: return None if "(" in member: # member contains name, extract ID member = member[member.rfind("(") + 1 : member.rfind(")")] return member def request_log(self, member=None, logNum=0): if member == None: member = self.get_selected_log_member() if member != None: self.logger.debug("Requesting log %d from %s", logNum, member) get_server().call( "HELO_REQUEST_LOGFILE %s %d" % (DataReceiverThread.getOpenPort(category="log%s" % member), logNum), set([member]), ) else: self.log_area.setText("No Member selected!") @loggingSlot() def requestLogClicked(self): self.requestLogsButton.setEnabled(False) self.dropdown_members.setEnabled(False) self.updateLogList([(0, None)]) self.request_log() def listLogFilesForMember(self, member): if member is None: return [] logDir = os.path.join(get_settings().get_main_config_dir(), "logs", member) if not os.path.exists(logDir): return [] return self.listLogfiles(logDir) def numLogFilesForMember(self, member): return len(self.listLogFilesForMember(member)) def requestTimedOut(self, item): if not sip.isdeleted(item) and item != None and item.data(0, Qt.UserRole) == None: self.log_tree_view.takeTopLevelItem(self.log_tree_view.indexFromItem(item).row()) self.requestFinished() def formatFileSize(self, num): for x in ["Bytes", "KB", "MB", "GB", "TB"]: if num < 1024.0: return "%3.1f %s" % (num, x) num /= 1024.0 def initializeLogItem(self, item, logFile): firstDate, lastDate = self.getLogDates(logFile) text = None tooltip = None if firstDate != None: text = firstDate.strftime("%Y-%m-%d %H:%M:%S") tooltip = u"File: %s\nFirst entry: %s\nLast entry: %s" % ( logFile, firstDate.strftime("%Y-%m-%d %H:%M:%S"), lastDate.strftime("%Y-%m-%d %H:%M:%S"), ) else: timestamp = datetime.fromtimestamp(os.path.getmtime(logFile)).strftime("%Y-%m-%d %H:%M:%S") text = u"%s" % os.path.basename(logFile) tooltip = u"File:%s\nModification Date: %s" % (logFile, timestamp) text = text + "\n%s" % self.formatFileSize(os.path.getsize(logFile)) if tooltip != None: item.setData(0, Qt.ToolTipRole, QVariant(tooltip)) item.setData(0, Qt.UserRole, logFile) item.setData(0, Qt.DisplayRole, QVariant(text)) @loggingSlot() def clearLogs(self): for aLogFile in self.listLogFilesForMember(self.get_selected_log_member()): os.remove(aLogFile) self.updateLogList() def updateLogList(self, logsAdded=None, logsRenamed=None): selectedMember = self.get_selected_log_member() if logsAdded == None: self.log_tree_view.clear() logsAdded = [] for index, logFile in enumerate(reversed(self.listLogFilesForMember(selectedMember))): logsAdded.append((index, logFile)) if len(logsAdded) == 0: self.log_tree_view.clear() self.log_tree_view.addTopLevelItem( QTreeWidgetItem(self.log_tree_view, QStringList("No logs available.")) ) self.log_tree_view.setSelectionMode(QTreeWidget.NoSelection) self.logSizeLabel.setText("No logs") self.clearLogsButton.setEnabled(False) return if logsRenamed != None: for index, oldName, newName in logsRenamed: # index + 1 because of the "requesting" item item = self.log_tree_view.topLevelItem(index + 1) if item != None: itemLogFile = convert_string(item.data(0, Qt.UserRole).toString()) if itemLogFile != oldName: self.logger.warning( "index does not correspond to item in list:\n\t%s\n\t%s", itemLogFile, oldName ) self.initializeLogItem(item, newName) if len(logsAdded) == 0: self.log_tree_view.takeTopLevelItem(0) else: for index, logFile in logsAdded: oldItem = self.log_tree_view.topLevelItem(index) item = None if oldItem != None and oldItem.data(0, Qt.UserRole) == None: # requested item has been received item = oldItem else: item = QTreeWidgetItem() oldItem = None if logFile == None: item.setData(0, Qt.DisplayRole, QVariant("Requesting...")) QTimer.singleShot(6000, partial(self.requestTimedOut, item)) else: self.initializeLogItem(item, logFile) if oldItem == None: # else, the old item is being modified self.log_tree_view.insertTopLevelItem(index, item) self.log_tree_view.setSelectionMode(QTreeWidget.SingleSelection) totalSize = 0 for aLogFile in self.listLogFilesForMember(selectedMember): totalSize += os.path.getsize(aLogFile) self.logSizeLabel.setText("%s consumed" % self.formatFileSize(totalSize)) self.clearLogsButton.setEnabled(True) # self.displaySelectedLogfile() def getSelectedLogContent(self): member = self.get_selected_log_member() if member == None: return "No Log selected." selection = self.log_tree_view.selectedIndexes() if len(selection) is 0: return "No Log selected." logPath = convert_string(selection[0].data(Qt.UserRole).toString()) if logPath == None: return "ERROR: path is None" if not os.path.exists(logPath): return "File not found: " + logPath fcontent = "" try: with codecs.open(logPath, "r", "utf8") as fhandler: fcontent = fhandler.read() except Exception as e: self.logger.exception("Error reading file") fcontent = "Error reading file: %s" % str(e) return fcontent @loggingSlot(QItemSelection, QItemSelection) def displaySelectedLogfile(self, _new, _old): self.log_area.setText(self.getSelectedLogContent()) @loggingSlot(int) def memberSelectionChanged(self, _new=None): self.updateLogList() isMemberSelected = self.get_selected_log_member() != None self.sendMessageButton.setEnabled(isMemberSelected) self.requestLogsButton.setEnabled(isMemberSelected) self.updateMemberInformation() @loggingSlot(object) def sendMessageToMember(self, lineEdit): selectedMember = self.get_selected_log_member() if selectedMember != None: get_server().call(convert_string(lineEdit.text()), set([selectedMember])) lineEdit.clear() @loggingSlot(object, object) def updateMemberInformation(self, peerID=None, peerInfo=None): if peerID != None and peerID != self.get_selected_log_member(): # only update if selected member updated return self.memberInformationTable.clear() if self.get_selected_log_member() == None: self.memberInformationTable.setColumnCount(0) self.memberInformationTable.setHeaderLabel("No member selected.") return if peerInfo == None: peerInfo = get_peers().getPeerInfo(pID=self.get_selected_log_member()) if peerInfo == None: self.memberInformationTable.setColumnCount(0) self.memberInformationTable.setHeaderLabel("No member information available.") return self.memberInformationTable.setColumnCount(len(peerInfo)) headers = sorted(peerInfo.keys(), key=lambda s: s.lower()) self.memberInformationTable.setHeaderLabels(QStringList(headers)) item = QTreeWidgetItem(self.memberInformationTable) for col, header in enumerate(headers): item.setData(col, Qt.DisplayRole, QVariant(peerInfo[header])) for col in range(self.memberInformationTable.columnCount()): self.memberInformationTable.resizeColumnToContents(col)
class EvtTableWidget(QTableWidget): def __init__(self, parent=None): QTableWidget.__init__(self, parent) self.setColumnCount(6) self.setHorizontalHeaderLabels(['level', 'id', 'date', 'source']) self.horizontalHeader().setStretchLastSection(True) self.verticalHeader().hide() self.setSortingEnabled(True) self.setSelectionBehavior(QAbstractItemView.SelectRows) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setEditTriggers(QAbstractItemView.NoEditTriggers) self.setShowGrid(False) self.setAlternatingRowColors(True) self.hideColumn(4) self.hideColumn(5) self.cellDoubleClicked.connect(self.dispSingleEvent) self.menu = EvtSelectorMenu(self) def selectedEvents(self): selected = [] for itemId in range(self.rowCount()): item = self.item(itemId, 0) if item.checkState() != Qt.Unchecked: selected.append(self.itemRecord(itemId)) if len(selected): return selected return None def mousePressEvent(self, e): index = self.indexAt(e.pos()) if index.isValid(): item = self.itemAt(e.pos()) if e.button() == Qt.RightButton: self.menu.popup(QCursor.pos()) QTableWidget.mousePressEvent(self, e) def select(self): for item in self.selectedItems(): if item.column() == 0: item.setCheckState(Qt.Checked) def unselect(self): for item in self.selectedItems(): if item.column() == 0: item.setCheckState(Qt.Unchecked) def selectAll(self): for itemId in range(self.rowCount()): item = self.item(itemId, 0) item.setCheckState(Qt.Checked) def unselectAll(self): for itemId in range(self.rowCount()): item = self.item(itemId, 0) item.setCheckState(Qt.Unchecked) def itemRecord(self, row): node_ptr = self.item(row, 4).text() index = int(self.item(row, 5).text()) processus_manager = ModuleProcessusManager() evt = processus_manager.get('evt') record = evt.evts[long(node_ptr)][index] return record def dispSingleEvent(self, row, column): box = QDialog() main_layout = QHBoxLayout(box) main_widget = QWidget() main_layout.addWidget(main_widget) layout = QVBoxLayout(main_widget) node_ptr = self.item(row, 4).text() index = int(self.item(row, 5).text()) processus_manager = ModuleProcessusManager() evt = processus_manager.get('evt') record = evt.evts[long(node_ptr)][index] self.label1 = QLabel("Date : " + record.getTimeGenerated()) self.label2 = QLabel("Source : " + record.sourceName()) self.label3 = QLabel("Type : " + record.getSingleType()) self.lab_icon = QLabel() self.lab_icon.setPixmap( QPixmap(record.getIcon()).scaled(32, 32, Qt.KeepAspectRatio)) weed = QWidget() l = QHBoxLayout(weed) l.addWidget(self.lab_icon) l.addWidget(self.label3) self.label4 = QLabel("Category : " + str(record.EventCategory)) self.label5 = QLabel("EventId : " + str(record.EventID)) self.label6 = QLabel("Computer : " + record.computerName()) layout.addWidget(self.subWidget(self.label1, self.label2)) layout.addWidget(self.subWidget(weed, self.label4)) layout.addWidget(self.subWidget(self.label5, self.label6)) layout.addWidget(QLabel('Messages :')) self.log_strings = QTextEdit('') self.log_strings.setReadOnly(True) self.log_strings.setLineWrapMode(QTextEdit.WidgetWidth) for log in record.getStrings(): if log is not None: self.log_strings.setPlainText(self.log_strings.toPlainText() + log + "\n\n") layout.addWidget(self.log_strings) button_widget = QWidget() main_layout.addWidget(button_widget) self.next_evt = QPushButton(QIcon(":/next.png"), "") self.next_evt.setToolTip("Next record") self.prev_evt = QPushButton(QIcon(":/previous.png"), "") self.prev_evt.setToolTip("Previous record") self.next_evt.clicked.connect(self.dispNextEvent) self.prev_evt.clicked.connect(self.dispPrevEvent) if row == 0: self.prev_evt.setEnabled(False) elif row + 1 == self.rowCount(): self.next_evt.setEnabled(False) else: self.hideOrDipsButton() button_layout = QVBoxLayout(button_widget) button_layout.addWidget(self.prev_evt) button_layout.addWidget(self.next_evt) spacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) button_layout.addItem(spacerItem) close_button = QPushButton("Close") close_button.clicked.connect(box.done) button_layout.addWidget(close_button) box.exec_() def subWidget(self, label1, label2): widget = QWidget() layout = QHBoxLayout(widget) layout.addWidget(label1) layout.addWidget(label2) return widget def dispNextEvent(self, checked): row = self.currentRow() + 1 while row + 1 != self.rowCount() and self.isRowHidden(row): row += 1 self.display(row) # is there a next record ? while row + 1 != self.rowCount(): row += 1 if not self.isRowHidden(row): return self.next_evt.setEnabled(False) def dispPrevEvent(self, checked): row = self.currentRow() - 1 while row != 0 and self.isRowHidden(row): row -= 1 self.display(row) # is there a previous record ? while row != 0: row -= 1 if not self.isRowHidden(row): return self.prev_evt.setEnabled(False) def display(self, row): self.setCurrentCell(row, 0) node_ptr = self.item(row, 4).text() index = int(self.item(row, 5).text()) processus_manager = ModuleProcessusManager() evt = processus_manager.get('evt') record = evt.evts[long(node_ptr)][index] self.label1.setText("Date : " + record.getTimeGenerated()) self.label2.setText("Source : " + record.sourceName()) self.lab_icon.setPixmap( QPixmap(record.getIcon()).scaled(32, 32, Qt.KeepAspectRatio)) self.label3.setText("Type : " + record.getSingleType()) self.label4.setText("Category : " + str(record.EventCategory)) self.label5.setText("EventId : " + str(record.EventID)) self.label6.setText("Computer : " + record.computerName()) self.log_strings.setPlainText('') for log in record.getStrings(): if log is not None: self.log_strings.setPlainText(self.log_strings.toPlainText() + log + "\n") self.hideOrDipsButton() def hideOrDipsButton(self): row = self.currentRow() if row == 0: self.prev_evt.setEnabled(False) else: self.prev_evt.setEnabled(True) if row + 1 == self.rowCount(): self.next_evt.setEnabled(False) else: self.next_evt.setEnabled(True) # is there a next record ? row = self.currentRow() next_e = False while row + 1 != self.rowCount(): row += 1 if not self.isRowHidden(row): next_e = True break if next_e == False: self.next_evt.setEnabled(False) row = self.currentRow() # is there a previous record ? prev_e = False while row != 0: row -= 1 if not self.isRowHidden(row): prev_e = True break if prev_e == False: self.prev_evt.setEnabled(False) def setItemFlags(self, item): item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) item.setCheckState(Qt.Checked) def addItemToTable(self, record, widget, rows, node_ptr, count): if count == -1: count = rows item = QTableWidgetItem(QIcon(record.getIcon()), str(record.getSingleType())) self.setItemFlags(item) widget.setItem(rows, 0, item) item = QTableWidgetItem(str(record.EventID)) widget.setItem(rows, 1, item) item = QTableWidgetItem(str(record.getTimeGenerated())) widget.setItem(rows, 2, item) item = QTableWidgetItem(str(record.sourceName())) widget.setItem(rows, 3, item) item = QTableWidgetItem(str(long(node_ptr))) widget.setItem(rows, 4, item) item = QTableWidgetItem(str(count)) widget.setItem(rows, 5, item)