def addMenuLabel(menu, text): """Adds a QLabel contaning text to the given menu""" qaw = QWidgetAction(menu) lab = QLabel(text, menu) qaw.setDefaultWidget(lab) lab.setAlignment(Qt.AlignCenter) lab.setFrameShape(QFrame.StyledPanel) lab.setFrameShadow(QFrame.Sunken) menu.addAction(qaw) return lab
def __init__(self, db, book_id_map, parent=None): from calibre.ebooks.oeb.polish.main import HELP QDialog.__init__(self, parent) self.db, self.book_id_map = weakref.ref(db), book_id_map self.setWindowIcon(QIcon(I('polish.png'))) title = _('Polish book') if len(book_id_map) > 1: title = _('Polish %d books')%len(book_id_map) self.setWindowTitle(title) self.help_text = { 'polish': _('<h3>About Polishing books</h3>%s')%HELP['about'].format( _('''<p>If you have both EPUB and ORIGINAL_EPUB in your book, then polishing will run on ORIGINAL_EPUB (the same for other ORIGINAL_* formats). So if you want Polishing to not run on the ORIGINAL_* format, delete the ORIGINAL_* format before running it.</p>''') ), 'embed':_('<h3>Embed referenced fonts</h3>%s')%HELP['embed'], 'subset':_('<h3>Subsetting fonts</h3>%s')%HELP['subset'], 'smarten_punctuation': _('<h3>Smarten punctuation</h3>%s')%HELP['smarten_punctuation'], 'metadata':_('<h3>Updating metadata</h3>' '<p>This will update all metadata <i>except</i> the cover in the' ' ebook files to match the current metadata in the' ' calibre library.</p>' ' <p>Note that most ebook' ' formats are not capable of supporting all the' ' metadata in calibre.</p><p>There is a separate option to' ' update the cover.</p>'), 'do_cover': _('<p>Update the covers in the ebook files to match the' ' current cover in the calibre library.</p>' '<p>If the ebook file does not have' ' an identifiable cover, a new cover is inserted.</p>' ), 'jacket':_('<h3>Book Jacket</h3>%s')%HELP['jacket'], 'remove_jacket':_('<h3>Remove Book Jacket</h3>%s')%HELP['remove_jacket'], } self.l = l = QGridLayout() self.setLayout(l) self.la = la = QLabel('<b>'+_('Select actions to perform:')) l.addWidget(la, 0, 0, 1, 2) count = 0 self.all_actions = OrderedDict([ ('embed', _('&Embed all referenced fonts')), ('subset', _('&Subset all embedded fonts')), ('smarten_punctuation', _('Smarten &punctuation')), ('metadata', _('Update &metadata in the book files')), ('do_cover', _('Update the &cover in the book files')), ('jacket', _('Add metadata as a "book &jacket" page')), ('remove_jacket', _('&Remove a previously inserted book jacket')), ]) prefs = gprefs.get('polishing_settings', {}) for name, text in self.all_actions.iteritems(): count += 1 x = QCheckBox(text, self) x.setChecked(prefs.get(name, False)) x.stateChanged.connect(partial(self.option_toggled, name)) l.addWidget(x, count, 0, 1, 1) setattr(self, 'opt_'+name, x) la = QLabel(' <a href="#%s">%s</a>'%(name, _('About'))) setattr(self, 'label_'+name, x) la.linkActivated.connect(self.help_link_activated) l.addWidget(la, count, 1, 1, 1) count += 1 l.addItem(QSpacerItem(10, 10, vPolicy=QSizePolicy.Expanding), count, 1, 1, 2) la = self.help_label = QLabel('') self.help_link_activated('#polish') la.setWordWrap(True) la.setTextFormat(Qt.RichText) la.setFrameShape(QFrame.StyledPanel) la.setAlignment(Qt.AlignLeft|Qt.AlignTop) la.setLineWidth(2) la.setStyleSheet('QLabel { margin-left: 75px }') l.addWidget(la, 0, 2, count+1, 1) l.setColumnStretch(2, 1) self.show_reports = sr = QCheckBox(_('Show &report'), self) sr.setChecked(gprefs.get('polish_show_reports', True)) sr.setToolTip(textwrap.fill(_('Show a report of all the actions performed' ' after polishing is completed'))) l.addWidget(sr, count+1, 0, 1, 1) self.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) self.save_button = sb = bb.addButton(_('&Save Settings'), bb.ActionRole) sb.clicked.connect(self.save_settings) self.load_button = lb = bb.addButton(_('&Load Settings'), bb.ActionRole) self.load_menu = QMenu(lb) lb.setMenu(self.load_menu) self.all_button = b = bb.addButton(_('Select &all'), bb.ActionRole) b.clicked.connect(partial(self.select_all, True)) self.none_button = b = bb.addButton(_('Select &none'), bb.ActionRole) b.clicked.connect(partial(self.select_all, False)) l.addWidget(bb, count+1, 1, 1, -1) self.setup_load_button() self.resize(QSize(950, 600))
def __init__(self, db, book_id_map, parent=None): from calibre.ebooks.oeb.polish.main import HELP QDialog.__init__(self, parent) self.db, self.book_id_map = weakref.ref(db), book_id_map self.setWindowIcon(QIcon(I('polish.png'))) title = _('Polish book') if len(book_id_map) > 1: title = _('Polish %d books')%len(book_id_map) self.setWindowTitle(title) self.help_text = { 'polish': _('<h3>About Polishing books</h3>%s')%HELP['about'].format( _('''<p>If you have both EPUB and ORIGINAL_EPUB in your book, then polishing will run on ORIGINAL_EPUB (the same for other ORIGINAL_* formats). So if you want Polishing to not run on the ORIGINAL_* format, delete the ORIGINAL_* format before running it.</p>''') ), 'embed':_('<h3>Embed referenced fonts</h3>%s')%HELP['embed'], 'subset':_('<h3>Subsetting fonts</h3>%s')%HELP['subset'], 'smarten_punctuation': _('<h3>Smarten punctuation</h3>%s')%HELP['smarten_punctuation'], 'metadata':_('<h3>Updating metadata</h3>' '<p>This will update all metadata <i>except</i> the cover in the' ' ebook files to match the current metadata in the' ' calibre library.</p>' ' <p>Note that most ebook' ' formats are not capable of supporting all the' ' metadata in calibre.</p><p>There is a separate option to' ' update the cover.</p>'), 'do_cover': _('<h3>Update cover</h3><p>Update the covers in the ebook files to match the' ' current cover in the calibre library.</p>' '<p>If the ebook file does not have' ' an identifiable cover, a new cover is inserted.</p>' ), 'jacket':_('<h3>Book Jacket</h3>%s')%HELP['jacket'], 'remove_jacket':_('<h3>Remove Book Jacket</h3>%s')%HELP['remove_jacket'], 'remove_unused_css':_('<h3>Remove unused CSS rules</h3>%s')%HELP['remove_unused_css'], } self.l = l = QGridLayout() self.setLayout(l) self.la = la = QLabel('<b>'+_('Select actions to perform:')) l.addWidget(la, 0, 0, 1, 2) count = 0 self.all_actions = OrderedDict([ ('embed', _('&Embed all referenced fonts')), ('subset', _('&Subset all embedded fonts')), ('smarten_punctuation', _('Smarten &punctuation')), ('metadata', _('Update &metadata in the book files')), ('do_cover', _('Update the &cover in the book files')), ('jacket', _('Add metadata as a "book &jacket" page')), ('remove_jacket', _('&Remove a previously inserted book jacket')), ('remove_unused_css', _('Remove &unused CSS rules from the book')), ]) prefs = gprefs.get('polishing_settings', {}) for name, text in self.all_actions.iteritems(): count += 1 x = QCheckBox(text, self) x.setChecked(prefs.get(name, False)) x.stateChanged.connect(partial(self.option_toggled, name)) l.addWidget(x, count, 0, 1, 1) setattr(self, 'opt_'+name, x) la = QLabel(' <a href="#%s">%s</a>'%(name, _('About'))) setattr(self, 'label_'+name, x) la.linkActivated.connect(self.help_link_activated) l.addWidget(la, count, 1, 1, 1) count += 1 l.addItem(QSpacerItem(10, 10, vPolicy=QSizePolicy.Expanding), count, 1, 1, 2) la = self.help_label = QLabel('') self.help_link_activated('#polish') la.setWordWrap(True) la.setTextFormat(Qt.RichText) la.setFrameShape(QFrame.StyledPanel) la.setAlignment(Qt.AlignLeft|Qt.AlignTop) la.setLineWidth(2) la.setStyleSheet('QLabel { margin-left: 75px }') l.addWidget(la, 0, 2, count+1, 1) l.setColumnStretch(2, 1) self.show_reports = sr = QCheckBox(_('Show &report'), self) sr.setChecked(gprefs.get('polish_show_reports', True)) sr.setToolTip(textwrap.fill(_('Show a report of all the actions performed' ' after polishing is completed'))) l.addWidget(sr, count+1, 0, 1, 1) self.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) self.save_button = sb = bb.addButton(_('&Save Settings'), bb.ActionRole) sb.clicked.connect(self.save_settings) self.load_button = lb = bb.addButton(_('&Load Settings'), bb.ActionRole) self.load_menu = QMenu(lb) lb.setMenu(self.load_menu) self.all_button = b = bb.addButton(_('Select &all'), bb.ActionRole) b.clicked.connect(partial(self.select_all, True)) self.none_button = b = bb.addButton(_('Select &none'), bb.ActionRole) b.clicked.connect(partial(self.select_all, False)) l.addWidget(bb, count+1, 1, 1, -1) self.setup_load_button() self.resize(QSize(950, 600))
class AppForm(QMainWindow): 'QT form for application' def __init__(self, splash,args,parent=None): self.starttime=None # start time of data self.endtime=None # end time of data self.bbox=args.b # geographical bounding box [w,e,s,n] self.preferredOrigin='p' # prefferred should be 'p': preferred origin ; 'f': first origin ; 'l': last origin self.includeunassoc=False # should we look also at unassociated origins (default - False) self.minmag=0 # minimum magnitude self.maxmag=10.0 # maximum magnitude self.deltaT=60.0 # absolute time difference in seconds to associate events self.deltaR=100.0 # absolute distance difference in km to associate events self._datadict = {} # dictionary of input events self._refdict = {} # dictionary of reference events self.data2reflut = {} # input to ref look up table self.ref2datalut = {} # ref to input look up table self.Bbox = bboxForm() self.Bbox.setLims(*self.bbox) splash.showMessage('Initializing...',Qt.AlignCenter) QApplication.processEvents() QMainWindow.__init__(self, parent) self.setWindowTitle('SC3 XML Diff') self.args = args # save command line arguments self.meter = mpl.lines.Line2D([],[],color='r') # line for measuring distances along canvas splash.showMessage('Creating application...',Qt.AlignCenter) QApplication.processEvents() self.create_menu() # create the app top menu self.create_status_bar() # add a status bar self.create_main_frame() # create the main frame. self.create_toolbox() # create a toolbox if args.i: splash.showMessage('Reading input data...',Qt.AlignCenter) QApplication.processEvents() self.get_input_file(args.i) if args.r: self.get_ref_file(args.r) splash.showMessage('Reading reference data...',Qt.AlignCenter) QApplication.processEvents() self.init_connections() # initialize signal connections splash.showMessage('Populating tables...',Qt.AlignCenter) QApplication.processEvents() self.updatetables() def init_connections(self): '''Connect signals to functions. Using signals to run functions from subprocesses.''' self.Bbox.accepted.connect(self.onBboxAccepted) # connect bbox to dialog ok button self.connect(self.minmagLine, SIGNAL('ok'),self.updateMagLims) self.connect(self.maxmagLine, SIGNAL('ok'),self.updateMagLims) self.connect(self.deltaTLine, SIGNAL('ok'),self.updateDeltaT) self.connect(self.deltaRLine, SIGNAL('ok'),self.updateDeltaR) self.starttimeLine.dateTimeChanged.connect(self.updatestarttime) self.endtimeLine.dateTimeChanged.connect(self.updateendtime) self.includeunassocLine.stateChanged.connect(self.updateUnassoc) self.preferredOriginLine.currentIndexChanged[str].connect(self.updatePreferredOrigin) # self.canvas.mpl_connect('button_press_event',self.on_click) # connect click on canvas # self.canvas.mpl_connect('button_release_event',self.on_unclick) # connect mouse button release on canvas # self.canvas.mpl_connect('motion_notify_event',self.on_move) # connect mouse motion on canvas def create_main_frame(self): 'Create the main frame of application' # create widget self.main_frame = QWidget() # create a general layout vbox = QVBoxLayout() # create a side by side layout for tables self.tb = self.addToolBar('Tools') # tool bar can be moved around self.tb.setMovable(True) self.tb.setFloatable(True) hsplit = QSplitter(Qt.Horizontal) self.headerlabels = HEADERLABELS ###################################### # create a layout for reference data # ###################################### vboxref = QVBoxLayout() # add a title label = QLabel('Reference Data') # create the reference table self.reftable = QTableWidget(0,len(self.headerlabels)) # Add header to table self.reftable.setHorizontalHeaderLabels(self.headerlabels) #self.reftable.setSortingEnabled(True) # settings for drag&drop self.reftable.setDragEnabled(True) self.reftable.setDragDropOverwriteMode(False) self.reftable.setDragDropMode(3) # can drag and drop # connect click events to row selection self.reftable.cellClicked.connect(self.reftable_cellClicked) # can select only rows self.reftable.setSelectionBehavior(QAbstractItemView.SelectRows) # no edits please #self.reftable.setEditTriggers(QAbstractItemView.NoEditTriggers) # No auto scrolling self.reftable.setAutoScroll(False) # connect drop events to adding events self.reftable.dropEvent = self.reftable_dropEvent # add label to ref layout vboxref.addWidget(label) # add table to ref layout vboxref.addWidget(self.reftable) ################################## # create a layout for input data # ################################## vboxdata = QVBoxLayout() # add a title label = QLabel('Input data') # create the input table self.datatable = QTableWidget(0,len(self.headerlabels)) # Add header to table self.datatable.setHorizontalHeaderLabels(self.headerlabels) #self.datatable.setSortingEnabled(True) # settings for drag&drop self.datatable.setDragEnabled(True) self.datatable.setDragDropOverwriteMode(False) self.datatable.setDragDropMode(3) # can drag and drop # connect click events to row selection self.datatable.cellClicked.connect(self.datatable_cellClicked) # can select only rows self.datatable.setSelectionBehavior(QAbstractItemView.SelectRows) # no edits please #self.datatable.setEditTriggers(QAbstractItemView.NoEditTriggers) # No auto scrolling self.datatable.setAutoScroll(False) # connect drop events to ID association self.datatable.dropEvent = self.datatable_dropEvent # add label to SC3 layout vboxdata.addWidget(label) # add table to SC3 layout vboxdata.addWidget(self.datatable) # Add layouts to side by side layout w = QWidget() w.setLayout(vboxref) hsplit.addWidget(w) w = QWidget() w.setLayout(vboxdata) hsplit.addWidget(w) # add side by side to general layout vbox.insertWidget(1,hsplit) # add layout to widget self.main_frame.setLayout(vbox) # set widget to be central widget self.setCentralWidget(self.main_frame) def reftable_cellClicked(self,row,col): 'any click on table will select the whole row' # select all row self.reftable.selectRow(row) # clear any selection in data table self.datatable.clearSelection() def datatable_cellClicked(self,row,col): 'any click on table will select the whole row' # select all row self.datatable.selectRow(row) # clear any selection in ref table self.reftable.clearSelection() def datatable_dropEvent(self,event): 'Associate ref event with input event if ref row is dragged and dropped on input row' if not event.source()==self.reftable: return # make sure row is from reference table if not self.datatable.itemAt(event.pos()): return # make sure we dropped reference row on an input row # get the referrence ID refID = str(event.source().selectedItems()[0].text()) # get the ID item on input table item = self.datatable.item(self.datatable.itemAt(event.pos()).row(),0) inputID = str(item.text()) # confirm with user to associate if refID in self.data2reflut or inputID in self.data2reflut: self.statusBar().showMessage('%s and/or %s are already associated. Aborting.'%(refID,inputID) , 2000) return ok = QMessageBox.question(self,'Associate Event', 'Are you sure you want to associate\n%s to %s?'%(refID,inputID), 'No','Yes') if ok: # update the lut self.ref2datalut[refID]=inputID self.data2reflut[inputID]=refID self.updateStatus() # report to status bar self.statusBar().showMessage('Associated %s with %s'%(refID,inputID) , 2000) def reftable_dropEvent(self,event): 'Add new events to reference table if input row is dragged and dropped on ref table' if not event.source()==self.datatable: return # make sure its an input row # get row items items = event.source().selectedItems() # get input ID ID = str(items[0].text()) # make sure ID is associated already if ID in self.data2reflut: self.statusBar().showMessage('Event %s already associated with %s'%(ID,self.data2reflut[ID]) , 2000) return # disable sorting self.datatable.setSortingEnabled(False) self.reftable.setSortingEnabled(False) #update lut self.data2reflut[ID]=ID self.ref2datalut[ID]=ID # add a new row to reference table i = self.reftable.rowCount() self.reftable.insertRow(i) # copy line from input table for j,item in enumerate(items): newitem = QTableWidgetItem(item.text()) self.reftable.setItem(i,j,newitem) # update status self.updateStatus() # sort ref table self.datatable.setSortingEnabled(True) self.reftable.setSortingEnabled(True) # report to statusbar self.statusBar().showMessage('Added Event %s'%(ID) , 2000) def delete_row(self): 'Delete a selected row from table' # get selected row(s) on SC3 table items = [i for i in self.datatable.selectedItems()+self.reftable.selectedItems() if i.column()==0] for item in items: # get selected row number row = item.row() # get event ID ID = str(item.text()) # remove the row from table item.tableWidget().removeRow(row) # remove lut records [self.data2reflut.pop(k) for k,v in self.data2reflut.items() if k==ID or v==ID] [self.ref2datalut.pop(k) for k,v in self.ref2datalut.items() if k==ID or v==ID] self.updateStatus() # report to statusbar self.statusBar().showMessage('Removed Event %s from table'%ID , 2000) if len(items)>1: self.statusBar().showMessage('%d Events removed from table'%len(items) , 2000) def clear_table(self,table): 'Clear a table' for i in range(table.rowCount())[::-1]: table.removeRow(i) def clear_tables(self): [self.clear_table(t) for t in [self.datatable,self.reftable]] def create_tooltip_widget(self): 'creates tooltip of figure elements' self.TTWidget = QLabel() # take a QLabel self.TTWidget.setFrameShape(QFrame.StyledPanel) # add a frame self.TTWidget.setWindowFlags(Qt.ToolTip) # make window look like a tooltip self.TTWidget.setAttribute(Qt.WA_TransparentForMouseEvents) # mouse events can't affet it. self.TTWidget.hide() # hide for now. see self.on_move function on how to use. def get_input_file(self,filesurl=None): 'open a dialog to get a file name' if not filesurl: filesurl = QFileDialog.getOpenFileNames(self, 'Open Input data file(s)',filter='*.xml') # get the file name self.ref2datalut={} # init look up table self.data2reflut={} # init look up table if len(filesurl): xmls = [str(f) for f in filesurl] Dataep = concatenateSC3XML(xmls) if not Dataep: self.statusBar().showMessage('No Events in file.', 2000) return self._datadict = eparams2seisEvents(Dataep,starttime=self.starttime,endtime=self.endtime,minmag=self.minmag,maxmag=self.maxmag,bbox=self.bbox,preferred=self.preferredOrigin,includeunassoc=self.includeunassoc) self.statusBar().showMessage('Loaded %d events'%len(self._datadict), 2000) self.updatetables() def get_ref_file(self,filesurl=None,refFileType=None): 'open a dialog to get a file name' if not filesurl: filesurl,refFileType = QFileDialog.getOpenFileNamesAndFilter(self, 'Open Reference data file(s)',filter='XML Files (*.xml);;CSV Files (*.csv)') # get the file name else: refFileType = os.path.splitext(filesurl[0])[1].upper() self.ref2datalut={}# init look up table self.data2reflut={}# init look up table if 'XML' in refFileType: xmls = [str(f) for f in filesurl] Refep = concatenateSC3XML(xmls) if not Refep: self.statusBar().showMessage('No Events in file.', 2000) return self._refdict = eparams2seisEvents(Refep,starttime=self.starttime,endtime=self.endtime,minmag=self.minmag,maxmag=self.maxmag,bbox=self.bbox,preferred=self.preferredOrigin,includeunassoc=self.includeunassoc) self.statusBar().showMessage('Loaded %d events'%len(self._refdict), 2000) return self.updatetables() if 'CSV' in refFileType: CSVs = [str(f) for f in filesurl] Refdb = concatenateCSV(CSVs) if not len(Refdb): self.statusBar().showMessage('No Events in file.', 2000) return self.updatetables() self._refdict = db2seisEvents(Refdb,starttime=self.starttime,endtime=self.endtime,minmag=self.minmag,maxmag=self.maxmag,bbox=self.bbox,preferred=self.preferredOrigin,includeunassoc=self.includeunassoc) self.statusBar().showMessage('Loaded %d events'%len(self._refdict), 2000) return self.updatetables() self.statusBar().showMessage("Can't load reference file(s)", 3000) def filterEvents(self,D): 'filter events by time,location and magnitude limits' [D.pop(i) for i in [k for k in D if D[k].mag>self.maxmag or D[k].mag<self.minmag]] if self.starttime: [D.pop(i) for i in [k for k in D if D[k].ot<self.starttime]] if self.endtime: [D.pop(i) for i in [k for k in D if D[k].ot>self.endtime]] [D.pop(i) for i in [k for k in D if D[k].lon>self.bbox[1] or D[k].lon<self.bbox[0]]] [D.pop(i) for i in [k for k in D if D[k].lat>self.bbox[3] or D[k].lat<self.bbox[2]]] return D def associate(self): 'associate events' self.ref2datalut = {} self.data2reflut = {} # filter unwanted events self.refdict = {} self.datadict = {} self.refdict.update(self._refdict) self.datadict.update(self._datadict) self.refdict = self.filterEvents(self.refdict) self.datadict= self.filterEvents(self.datadict) for ref in self.refdict.keys(): # get potentials associated events for reference. (time diff,seisevent obj) list potentials = [(abs(self.datadict[k].ot-self.refdict[ref].ot).total_seconds(),k) for k in self.datadict if abs(self.datadict[k].ot-self.refdict[ref].ot).total_seconds()<=self.deltaT and (self.datadict[k]-self.refdict[ref])[-1]/1000.0<=self.deltaR] potentials.sort() # sort according to time difference if potentials: self.ref2datalut[ref] = potentials[0][1] # get first one. self.data2reflut[potentials[0][1]] = ref def recolor_table(self,table): ' add colors to lines. Green - True event, Red - false event, orange - missed event' # mark missed events on table stat = HEADERLABELS.index('Status') for i in xrange(table.rowCount()): table.selectRow(i) for item in table.selectedItems(): f = item.foreground() if str(table.item(i,stat).text())=='M': f.setColor(QColor('#FFA500')) elif str(table.item(i,stat).text())=='F': f.setColor(QColor('red')) elif str(table.item(i,stat).text())=='T': f.setColor(QColor('k')) item.setForeground(f) table.clearSelection() def recolor_tables(self): [self.recolor_table(table) for table in [self.datatable,self.reftable]] def build_tables(self): 'populate the gui tables from dictionaries' # populate ref table self.reftable.setSortingEnabled(False) for i,e in enumerate(self.refdict): # add a row self.reftable.insertRow(i) # create an ID item item = QTableWidgetItem(e) # add ID to row self.reftable.setItem(i,0,item) # insert event date to row for j,v in enumerate([self.refdict[e].__dict__[k] for k in ['ot','mag','lat','lon','status','refid','SCevaluationStatus']]): item = QTableWidgetItem(str(v)) self.reftable.setItem(i,j+1,item) # sort the table self.reftable.setSortingEnabled(True) # adjust columns size self.reftable.resizeColumnsToContents() # populate data table self.datatable.setSortingEnabled(False) for i,e in enumerate(self.datadict): # add a row self.datatable.insertRow(i) # create an ID cell item = QTableWidgetItem(e) # add ID to row self.datatable.setItem(i,0,item) # insert event date to row for j,v in enumerate([self.datadict[e].__dict__[k] for k in ['ot','mag','lat','lon','status','refid','SCevaluationStatus']]): item = QTableWidgetItem(str(v)) self.datatable.setItem(i,j+1,item) # sort the table self.datatable.setSortingEnabled(True) # adjust columns size self.datatable.resizeColumnsToContents() # update status self.updateStatus() def updateStatus(self): 'update status of event (T,M,F)' # referrece table stat = HEADERLABELS.index('Status') refID = HEADERLABELS.index('refID') self.reftable.setSortingEnabled(False) for i in xrange(self.reftable.rowCount()): ID = str(self.reftable.item(i,0).text()) if ID in self.ref2datalut: self.reftable.item(i,stat).setText('T') self.reftable.item(i,refID).setText(self.ref2datalut[ID]) else: self.reftable.item(i,stat).setText('M') self.reftable.item(i,refID).setText('') self.reftable.setSortingEnabled(True) self.datatable.setSortingEnabled(False) for i in xrange(self.datatable.rowCount()): ID = str(self.datatable.item(i,0).text()) if ID in self.data2reflut: self.datatable.item(i,stat).setText('T') self.datatable.item(i,refID).setText(self.data2reflut[ID]) else: self.datatable.item(i,stat).setText('F') self.datatable.item(i,refID).setText('') self.datatable.setSortingEnabled(True) # repaint missed False and true events self.recolor_tables() def updatetables(self): self.associate() self.clear_tables() self.build_tables() self.statusBar().showMessage('Tables updated',2000) def updateMagLims(self): self.minmag = float(self.minmagLine.text()) self.maxmag = float(self.maxmagLine.text()) self.statusBar().showMessage('Magnitude limits updated',2000) def updateDeltaT(self): self.deltaT = float(self.deltaTLine.text()) self.statusBar().showMessage('Association time limit updated',2000) def updateDeltaR(self): self.deltaR = float(self.deltaRLine.text()) self.statusBar().showMessage('Association distance limit updated',2000) def updatestarttime(self,starttime): self.starttime = starttime.toPyDateTime() self.statusBar().showMessage('Start time limit updated',2000) def updateendtime(self,endtime): self.endtime = endtime.toPyDateTime() self.statusBar().showMessage('End time limit updated',2000) def updateUnassoc(self,stat): self.includeunassoc = bool(stat) self.statusBar().showMessage('Including unassociated origins set to %s'%self.includeunassoc,2000) def updatePreferredOrigin(self,pref): self.preferredOrigin = pref[0] self.statusBar().showMessage('Preferred Origins set to %s'%pref,2000) def evaluate(self): i = self.headerlabels.index('Status') table = self.datatable T = len([table.item(j,i) for j in xrange(table.rowCount()) if str(table.item(j,i).text())=='T']) F = len([table.item(j,i) for j in xrange(table.rowCount()) if str(table.item(j,i).text())=='F']) table = self.reftable M = len([table.item(j,i) for j in xrange(table.rowCount()) if str(table.item(j,i).text())=='M']) self.statusBar().showMessage('T: %d ; M: %d ; F: %d ; Score: %.1f%% for %d events'%(T,M,F,100.0*T/sum([T,F,M]),sum([T,F,M])), 5000) return T,F,M,100.0*T/sum([T,F,M]) def saveAs_figure(self): pass def create_menu(self): 'Creates main menu' # Populate the menubar: # Add File submenu self.file_menu = self.menuBar().addMenu("&File") # load input data load_input_action = self.create_action("Load &Input", shortcut="Ctrl+I", slot=self.get_input_file, icon='document-open',tip="Load input data from a file(s)") # load reference data load_ref_action = self.create_action("Load &Reference", shortcut="Ctrl+R", slot=self.get_ref_file, icon='document-open',tip="Load reference data from a file(s)") # Save As... saveAs_action = self.create_action("S&ave As...", shortcut="Shift+S", slot=self.saveAs_figure, icon='filesaveas',tip="Save the figure") # Quit quit_action = self.create_action("&Quit", slot=self.close, icon='system-shutdown',shortcut="Ctrl+Q", tip="Close the application") # populate the file submenu self.add_actions(self.file_menu, (load_input_action,load_ref_action, saveAs_action, None, quit_action)) # Add Edit submenu self.Edit_menu = self.menuBar().addMenu("&Edit") # delete an event delete_action = self.create_action("&Delete", slot=self.delete_row,shortcut="Del", tip="Delete selected row from table") # populate tools submenu self.add_actions(self.Edit_menu,[delete_action]) # Add help submenu self.help_menu = self.menuBar().addMenu("&Help") # Help help_action = self.create_action("&Help", shortcut='F1', slot=self.on_help, icon='Help',tip='help') # About about_action = self.create_action("&About", shortcut='F2', slot=self.on_about, tip='About This Application') # About QT aboutQt_action = self.create_action("&About QT", shortcut='F3', slot=self.on_aboutQt, tip='About QT') # License license_action = self.create_action("&License", shortcut='F4', slot=self.on_license, tip='Application License') # Populate help submenu self.add_actions(self.help_menu, (help_action,None,about_action,aboutQt_action,license_action)) def create_toolbox(self): w = QWidget() l = QGridLayout(w) self.refreshbutton = self.create_pushButton('Refresh', slot=self.updatetables, shortcut=None, icon=None, tip='Refresh Tables') self.scorebutton = self.create_pushButton('Score', slot=self.evaluate, shortcut=None, icon=None, tip='Evaluate Score') l.addWidget(self.refreshbutton,0,0) l.addWidget(self.scorebutton,1,0) self.tb.addWidget(w) w = QWidget() l = QGridLayout(w) self.minmagLine = ConnectedLineEdit(str(self.minmag),0,self.maxmag) self.maxmagLine = ConnectedLineEdit(str(self.maxmag),self.minmag,10) self.minmagLine.setConnected(self.maxmagLine, 'bottom') self.maxmagLine.setConnected(self.minmagLine, 'top') l.addWidget(QLabel('Magnitude Limits'),0,1) l.addWidget(QLabel('Min'),1,0) l.addWidget(QLabel('Max'),2,0) l.addWidget(self.minmagLine,1,1) l.addWidget(self.maxmagLine,2,1) self.tb.addWidget(w) w = QWidget() l = QGridLayout(w) self.deltaTLine = ConnectedLineEdit(str(self.deltaT),0,18000,3) self.deltaRLine = ConnectedLineEdit(str(self.deltaR),0,1000,3) l.addWidget(QLabel('Association Limits'),0,1) l.addWidget(QLabel('Time (sec)'),1,0) l.addWidget(QLabel('Range (km)'),2,0) l.addWidget(self.deltaTLine,1,1) l.addWidget(self.deltaRLine,2,1) self.tb.addWidget(w) w = QWidget() v = QVBoxLayout(w) ww = QWidget() v.addWidget(ww) l = QGridLayout(ww) W,E,S,N = self.bbox self.EAST = QLabel(str(E)) self.WEST = QLabel(str(W)) self.NORTH = QLabel(str(N)) self.SOUTH = QLabel(str(S)) self.bboxbutton = self.create_pushButton('Region', slot=self.Bbox.show, shortcut=None, icon=None, tip='Define a geographic region') l.addWidget(self.EAST,1,2,1,1,Qt.Alignment(Qt.AlignLeft)) l.addWidget(self.WEST,1,0,1,1,Qt.Alignment(Qt.AlignRight)) l.addWidget(self.NORTH,0,1,1,1,Qt.Alignment(Qt.AlignHCenter)) l.addWidget(self.SOUTH,2,1,1,1,Qt.Alignment(Qt.AlignHCenter)) v.addWidget(self.bboxbutton) self.tb.addWidget(w) w = QWidget() l = QGridLayout(w) self.starttimeLine = QDateTimeEdit() self.starttimeLine.setDisplayFormat('yyyy-MM-dd HH:mm:ss') self.starttimeLine.setCalendarPopup(True) self.endtimeLine = QDateTimeEdit() self.endtimeLine.setDateTime(QDateTime.currentDateTimeUtc()) self.endtimeLine.setDisplayFormat('yyyy-MM-dd HH:mm:ss') self.endtimeLine.setCalendarPopup(True) l.addWidget(QLabel('Start:'),0,0) l.addWidget(self.starttimeLine,0,1) l.addWidget(QLabel('End:'),1,0) l.addWidget(self.endtimeLine,1,1) self.tb.addWidget(w) w = QWidget() l = QGridLayout(w) self.preferredOriginLine = QComboBox() self.preferredOriginLine.addItems(['preferred','first','last']) self.includeunassocLine = QCheckBox('Unassociated') self.includeunassocLine.setCheckState(self.includeunassoc) l.addWidget(QLabel('Origins:'),0,0) l.addWidget(self.preferredOriginLine,1,0) l.addWidget(self.includeunassocLine,2,0) self.tb.addWidget(w) def onBboxAccepted(self): '''get region limits from BboxForm. fires when Bbox is accepted''' if self.Bbox.validate(): # make sure limits are acceptable self.bbox = self.Bbox.getLims() # get limits w,e,s,n = self.bbox self.WEST.setText(str(w)) self.EAST.setText(str(e)) self.NORTH.setText(str(n)) self.SOUTH.setText(str(s)) def add_actions(self, target, actions): 'Utility function for menu creation' for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def create_action( self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): 'Utility function for menu actions creation' action = QAction(text, self) action.setIconVisibleInMenu(True) if icon is not None: i = QIcon.fromTheme(icon,QIcon(":/%s.png" % icon)) action.setIcon(i) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: self.connect(action, SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action def create_pushButton(self,text,toolbar=None, slot=None, shortcut=None, icon=None, tip=None): 'Utility function for button creation' # create the button button = QPushButton(text,self) # populate properties if slot: # connect a function button.clicked.connect(slot) if icon: # add icon i = QIcon.fromTheme(icon,QIcon(":/%s.png" % icon)) button.setIcon(i) button.setIconSize(QSize(24,24)) if shortcut: # set the shortcut button.setShortcut(shortcut) if tip: # add tooltip and status tip button.setToolTip(tip) button.setStatusTip(tip) if toolbar: # add the button to a toolbar (or any widget) toolbar.addWidget(button) return button def create_status_bar(self): 'Add a status bar' # set default message self.status_text = QLabel("Ready") self.connstatLabel = QLabel() self.statusBar().addWidget(self.status_text, 1) self.statusBar().addPermanentWidget(self.connstatLabel) def on_about(self): 'show a messagebox about the application' msg = "<p align='center'><big>SCxmlDiff</big><br><br> \ Compare two Seiscomp3 XML files<br><br> \ <small>Created<br> \ by<br> \ Ran Novitsky Nof @ BSL, 2015</small><br><br>\ <a href='http://ran.rnof.info/'>http://ran.rnof.info</a><p>" QMessageBox.about(self,"About", msg.strip()) def on_aboutQt(self): 'show a messagebox about QT' QMessageBox.aboutQt(self,'') def on_license(self): 'GPL licanse message' msg = "<p><b>This</b> is a free software; you can redistribute it and/or modify it under the \ terms of the GNU General Public License as published by the Free Software \ Foundation; either version 3 of the License, or (at your option) any later \ version.</p>\ <p><b>This application</b> is distributed in the hope that it will be useful, but WITHOUT ANY \ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR \ A PARTICULAR PURPOSE. See the GNU General Public License for more details.</p> \ <p>You should have received a copy of the GNU General Public License along with \ this application; if not, see <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.</p>" QMessageBox.about(self,"Application Licanse", msg.strip()) def on_help(self): 'Show help on a message window. Uses the argparse help' msg = '<pre>'+parser.format_help()#.replace('\n','</p><p>') msg = msg.replace('*****@*****.**',"<a href='mailto:[email protected]'>[email protected]</a>").strip()+'<\pre>' QMessageBox.about(self,"Help", msg) def message(self,msg,title='Error'): 'a simple message window' QMessageBox.about(self,title,msg)