class HydroprintGUI(myqt.DialogWindow): ConsoleSignal = QSignal(str) def __init__(self, datamanager, parent=None): super(HydroprintGUI, self).__init__(parent, maximize=True) self.__updateUI = True # Child widgets: self.dmngr = datamanager self.dmngr.wldsetChanged.connect(self.wldset_changed) self.dmngr.wxdsetChanged.connect(self.wxdset_changed) self.page_setup_win = PageSetupWin(self) self.page_setup_win.newPageSetupSent.connect(self.layout_changed) self.color_palette_win = ColorsSetupWin(self) self.color_palette_win.newColorSetupSent.connect(self.update_colors) # Memory path variable: self.save_fig_dir = self.workdir # Generate UI: self.__initUI__() def __initUI__(self): # ---- Toolbar self.btn_save = btn_save = QToolButtonNormal(icons.get_icon('save')) btn_save.setToolTip('Save the well hydrograph') # btn_draw is usefull for debugging purposes btn_draw = QToolButtonNormal(icons.get_icon('refresh')) btn_draw.setToolTip('Force a refresh of the well hydrograph') btn_draw.hide() self.btn_load_layout = QToolButtonNormal( icons.get_icon('load_graph_config')) self.btn_load_layout.setToolTip( "<p>Load graph layout for the current water level " " datafile if it exists</p>") self.btn_load_layout.clicked.connect(self.load_layout_isClicked) self.btn_save_layout = QToolButtonNormal( icons.get_icon('save_graph_config')) self.btn_save_layout.setToolTip('Save current graph layout') self.btn_save_layout.clicked.connect(self.save_layout_isClicked) btn_bestfit_waterlvl = QToolButtonNormal(icons.get_icon('fit_y')) btn_bestfit_waterlvl.setToolTip('Best fit the water level scale') btn_bestfit_time = QToolButtonNormal(icons.get_icon('fit_x')) btn_bestfit_time.setToolTip('Best fit the time scale') self.btn_page_setup = QToolButtonNormal(icons.get_icon('page_setup')) self.btn_page_setup.setToolTip('Show the page setup window') self.btn_page_setup.clicked.connect(self.page_setup_win.show) btn_color_pick = QToolButtonNormal(icons.get_icon('color_picker')) btn_color_pick.setToolTip('<p>Show a window to setup the color palette' ' used to draw the hydrograph</p.') btn_color_pick.clicked.connect(self.color_palette_win.show) self.btn_language = LangToolButton() self.btn_language.setToolTip( "Set the language of the text shown in the graph.") self.btn_language.sig_lang_changed.connect(self.layout_changed) self.btn_language.setIconSize(icons.get_iconsize('normal')) # ---- Zoom Panel btn_zoom_out = QToolButtonSmall(icons.get_icon('zoom_out')) btn_zoom_out.setToolTip('Zoom out (ctrl + mouse-wheel-down)') btn_zoom_out.clicked.connect(self.zoom_out) btn_zoom_in = QToolButtonSmall(icons.get_icon('zoom_in')) btn_zoom_in.setToolTip('Zoom in (ctrl + mouse-wheel-up)') btn_zoom_in.clicked.connect(self.zoom_in) self.zoom_disp = QSpinBox() self.zoom_disp.setAlignment(Qt.AlignCenter) self.zoom_disp.setButtonSymbols(QAbstractSpinBox.NoButtons) self.zoom_disp.setReadOnly(True) self.zoom_disp.setSuffix(' %') self.zoom_disp.setRange(0, 9999) self.zoom_disp.setValue(100) zoom_pan = myqt.QFrameLayout() zoom_pan.setSpacing(3) zoom_pan.addWidget(btn_zoom_out, 0, 0) zoom_pan.addWidget(btn_zoom_in, 0, 1) zoom_pan.addWidget(self.zoom_disp, 0, 2) # LAYOUT : btn_list = [btn_save, btn_draw, self.btn_load_layout, self.btn_save_layout, VSep(), btn_bestfit_waterlvl, btn_bestfit_time, VSep(), self.btn_page_setup, btn_color_pick, self.btn_language, VSep(), zoom_pan] subgrid_toolbar = QGridLayout() toolbar_widget = QWidget() row = 0 for col, btn in enumerate(btn_list): subgrid_toolbar.addWidget(btn, row, col) subgrid_toolbar.setSpacing(5) subgrid_toolbar.setContentsMargins(0, 0, 0, 0) subgrid_toolbar.setColumnStretch(col + 1, 100) toolbar_widget.setLayout(subgrid_toolbar) # ---- LEFT PANEL # SubGrid Hydrograph Frame : self.hydrograph = hydrograph.Hydrograph() self.hydrograph_scrollarea = mplFigViewer.ImageViewer() self.hydrograph_scrollarea.zoomChanged.connect(self.zoom_disp.setValue) grid_hydrograph = QGridLayout() grid_hydrograph.addWidget(self.hydrograph_scrollarea, 0, 0) grid_hydrograph.setRowStretch(0, 500) grid_hydrograph.setColumnStretch(0, 500) grid_hydrograph.setContentsMargins(0, 0, 0, 0) # (L, T, R, B) # ASSEMBLING SubGrids : grid_layout = QGridLayout() self.grid_layout_widget = QFrame() row = 0 grid_layout.addWidget(toolbar_widget, row, 0) row += 1 grid_layout.addLayout(grid_hydrograph, row, 0) grid_layout.setContentsMargins(0, 0, 0, 0) # (L, T, R, B) grid_layout.setSpacing(5) grid_layout.setColumnStretch(0, 500) grid_layout.setRowStretch(1, 500) self.grid_layout_widget.setLayout(grid_layout) # ---- Right Panel self.tabscales = self.__init_scalesTabWidget__() self.right_panel = myqt.QFrameLayout() self.right_panel.addWidget(self.dmngr, 0, 0) self.right_panel.addWidget(self.tabscales, 1, 0) self.right_panel.setRowStretch(2, 100) self.right_panel.setSpacing(15) # ---- MAIN GRID mainGrid = QGridLayout() mainGrid.addWidget(self.grid_layout_widget, 0, 0) mainGrid.addWidget(VSep(), 0, 1) mainGrid.addWidget(self.right_panel, 0, 2) mainGrid.setContentsMargins(10, 10, 10, 10) # (L, T, R, B) mainGrid.setSpacing(15) mainGrid.setColumnStretch(0, 500) mainGrid.setColumnMinimumWidth(2, 250) self.setLayout(mainGrid) # ---- EVENTS # Toolbox Layout : btn_bestfit_waterlvl.clicked.connect(self.best_fit_waterlvl) btn_bestfit_time.clicked.connect(self.best_fit_time) btn_draw.clicked.connect(self.draw_hydrograph) btn_save.clicked.connect(self.select_save_path) # Hydrograph Layout : self.Ptot_scale.valueChanged.connect(self.layout_changed) self.qweather_bin.currentIndexChanged.connect(self.layout_changed) # ---- Init Image self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) def __init_scalesTabWidget__(self): class QRowLayout(QGridLayout): def __init__(self, items, parent=None): super(QRowLayout, self).__init__(parent) for col, item in enumerate(items): self.addWidget(item, 0, col) self.setContentsMargins(0, 0, 0, 0) self.setColumnStretch(0, 100) # ---- Time axis properties # Generate the widgets : self.date_start_widget = QDateEdit() self.date_start_widget.setDisplayFormat('01 / MM / yyyy') self.date_start_widget.setAlignment(Qt.AlignCenter) self.date_start_widget.dateChanged.connect(self.layout_changed) self.date_end_widget = QDateEdit() self.date_end_widget.setDisplayFormat('01 / MM / yyyy') self.date_end_widget.setAlignment(Qt.AlignCenter) self.date_end_widget.dateChanged.connect(self.layout_changed) self.time_scale_label = QComboBox() self.time_scale_label.setEditable(False) self.time_scale_label.setInsertPolicy(QComboBox.NoInsert) self.time_scale_label.addItems(['Month', 'Year']) self.time_scale_label.setCurrentIndex(0) self.time_scale_label.currentIndexChanged.connect(self.layout_changed) self.dateDispFreq_spinBox = QSpinBox() self.dateDispFreq_spinBox.setSingleStep(1) self.dateDispFreq_spinBox.setMinimum(1) self.dateDispFreq_spinBox.setMaximum(100) self.dateDispFreq_spinBox.setValue( self.hydrograph.date_labels_pattern) self.dateDispFreq_spinBox.setAlignment(Qt.AlignCenter) self.dateDispFreq_spinBox.setKeyboardTracking(False) self.dateDispFreq_spinBox.valueChanged.connect(self.layout_changed) # Setting up the layout : widget_time_scale = QFrame() widget_time_scale.setFrameStyle(0) grid_time_scale = QGridLayout() GRID = [[QLabel('From :'), self.date_start_widget], [QLabel('To :'), self.date_end_widget], [QLabel('Scale :'), self.time_scale_label], [QLabel('Date Disp. Pattern:'), self.dateDispFreq_spinBox]] for i, ROW in enumerate(GRID): grid_time_scale.addLayout(QRowLayout(ROW), i, 1) grid_time_scale.setVerticalSpacing(5) grid_time_scale.setContentsMargins(10, 10, 10, 10) widget_time_scale.setLayout(grid_time_scale) # ----- Water level axis properties # Widget : self.waterlvl_scale = QDoubleSpinBox() self.waterlvl_scale.setSingleStep(0.05) self.waterlvl_scale.setMinimum(0.05) self.waterlvl_scale.setSuffix(' m') self.waterlvl_scale.setAlignment(Qt.AlignCenter) self.waterlvl_scale.setKeyboardTracking(False) self.waterlvl_scale.valueChanged.connect(self.layout_changed) self.waterlvl_scale.setFixedWidth(100) self.waterlvl_max = QDoubleSpinBox() self.waterlvl_max.setSingleStep(0.1) self.waterlvl_max.setSuffix(' m') self.waterlvl_max.setAlignment(Qt.AlignCenter) self.waterlvl_max.setMinimum(-1000) self.waterlvl_max.setMaximum(1000) self.waterlvl_max.setKeyboardTracking(False) self.waterlvl_max.valueChanged.connect(self.layout_changed) self.waterlvl_max.setFixedWidth(100) self.NZGridWL_spinBox = QSpinBox() self.NZGridWL_spinBox.setSingleStep(1) self.NZGridWL_spinBox.setMinimum(1) self.NZGridWL_spinBox.setMaximum(50) self.NZGridWL_spinBox.setValue(self.hydrograph.NZGrid) self.NZGridWL_spinBox.setAlignment(Qt.AlignCenter) self.NZGridWL_spinBox.setKeyboardTracking(False) self.NZGridWL_spinBox.valueChanged.connect(self.layout_changed) self.NZGridWL_spinBox.setFixedWidth(100) self.datum_widget = QComboBox() self.datum_widget.addItems(['Ground Surface', 'Sea Level']) self.datum_widget.currentIndexChanged.connect(self.layout_changed) # Layout : subgrid_WLScale = QGridLayout() GRID = [[QLabel('Minimum :'), self.waterlvl_max], [QLabel('Scale :'), self.waterlvl_scale], [QLabel('Grid Divisions :'), self.NZGridWL_spinBox], [QLabel('Datum :'), self.datum_widget]] for i, ROW in enumerate(GRID): subgrid_WLScale.addLayout(QRowLayout(ROW), i, 1) subgrid_WLScale.setVerticalSpacing(5) subgrid_WLScale.setContentsMargins(10, 10, 10, 10) # (L, T, R, B) WLScale_widget = QFrame() WLScale_widget.setFrameStyle(0) WLScale_widget.setLayout(subgrid_WLScale) # ---- Weather Axis # Widgets : self.Ptot_scale = QSpinBox() self.Ptot_scale.setSingleStep(5) self.Ptot_scale.setMinimum(5) self.Ptot_scale.setMaximum(500) self.Ptot_scale.setValue(20) self.Ptot_scale.setSuffix(' mm') self.Ptot_scale.setAlignment(Qt.AlignCenter) self.qweather_bin = QComboBox() self.qweather_bin.setEditable(False) self.qweather_bin.setInsertPolicy(QComboBox.NoInsert) self.qweather_bin.addItems(['day', 'week', 'month']) self.qweather_bin.setCurrentIndex(1) # Layout : layout = QGridLayout() GRID = [[QLabel('Precip. Scale :'), self.Ptot_scale], [QLabel('Resampling :'), self.qweather_bin]] for i, row in enumerate(GRID): layout.addLayout(QRowLayout(row), i, 1) layout.setVerticalSpacing(5) layout.setContentsMargins(10, 10, 10, 10) # (L,T,R,B) layout.setRowStretch(i+1, 100) widget_weather_scale = QFrame() widget_weather_scale.setFrameStyle(0) widget_weather_scale.setLayout(layout) # ---- ASSEMBLING TABS tabscales = QTabWidget() tabscales.addTab(widget_time_scale, 'Time') tabscales.addTab(WLScale_widget, 'Water Level') tabscales.addTab(widget_weather_scale, 'Weather') return tabscales @property def workdir(self): return self.dmngr.workdir # ---- Utilities def zoom_in(self): self.hydrograph_scrollarea.zoomIn() def zoom_out(self): self.hydrograph_scrollarea.zoomOut() def update_colors(self): self.hydrograph.update_colors() self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) # ---- Datasets Handlers @property def wldset(self): return self.dmngr.get_current_wldset() @property def wxdset(self): return self.dmngr.get_current_wxdset() def wldset_changed(self): """Handle when the water level dataset of the datamanager changes.""" if self.wldset is None: self.clear_hydrograph() return else: self.hydrograph.set_wldset(self.wldset) self.hydrograph.gluedf = self.wldset.get_glue_at(-1) # Load the manual measurements. fname = os.path.join( self.workdir, "Water Levels", 'waterlvl_manual_measurements') tmeas, wlmeas = load_waterlvl_measures(fname, self.wldset['Well']) self.wldset.set_wlmeas(tmeas, wlmeas) # Setup the layout of the hydrograph. layout = self.wldset.get_layout() if layout is not None: msg = ("Loading existing graph layout for well %s." % self.wldset['Well']) print(msg) self.ConsoleSignal.emit('<font color=black>%s</font>' % msg) self.load_graph_layout(layout) else: print('No graph layout exists for well %s.' % self.wldset['Well']) # Fit Water Level in Layout : self.__updateUI = False self.best_fit_waterlvl() self.best_fit_time() if self.dmngr.set_closest_wxdset() is None: self.draw_hydrograph() self.__updateUI = True def wxdset_changed(self): """Handle when the weather dataset of the datamanager changes.""" if self.wldset is None: self.clear_hydrograph() else: self.hydrograph.set_wxdset(self.wxdset) QCoreApplication.processEvents() self.draw_hydrograph() # ---- Draw Hydrograph Handlers def best_fit_waterlvl(self): wldset = self.dmngr.get_current_wldset() if wldset is not None: WLscale, WLmin = self.hydrograph.best_fit_waterlvl() self.waterlvl_scale.setValue(WLscale) self.waterlvl_max.setValue(WLmin) def best_fit_time(self): wldset = self.dmngr.get_current_wldset() if wldset is not None: date0, date1 = self.hydrograph.best_fit_time(wldset.xldates) self.date_start_widget.setDate(QDate(date0[0], date0[1], date0[2])) self.date_end_widget.setDate(QDate(date1[0], date1[1], date1[2])) @QSlot() def mrc_wl_changed(self): """ Force a redraw of the MRC water levels after the results have changed for the dataset. """ self.hydrograph.draw_mrc_wl() self.hydrograph.setup_legend() self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) @QSlot(GLUEDataFrameBase) def glue_wl_changed(self, gluedf): """ Force a redraw of the GLUE water levels after the results have changed for the dataset. """ self.hydrograph.set_gluedf(gluedf) self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) def layout_changed(self): """ When an element of the graph layout is changed in the UI. """ if self.__updateUI is False: return self.update_graph_layout_parameter() if self.hydrograph.isHydrographExists is False: return sender = self.sender() if sender == self.btn_language: self.hydrograph.draw_ylabels() self.hydrograph.setup_xticklabels() self.hydrograph.setup_legend() elif sender in [self.waterlvl_max, self.waterlvl_scale]: self.hydrograph.setup_waterlvl_scale() self.hydrograph.draw_ylabels() elif sender == self.NZGridWL_spinBox: self.hydrograph.setup_waterlvl_scale() self.hydrograph.update_precip_scale() self.hydrograph.draw_ylabels() elif sender == self.Ptot_scale: self.hydrograph.update_precip_scale() self.hydrograph.draw_ylabels() elif sender == self.datum_widget: yoffset = int(self.wldset['Elevation']/self.hydrograph.WLscale) yoffset *= self.hydrograph.WLscale self.hydrograph.WLmin = (yoffset - self.hydrograph.WLmin) self.waterlvl_max.blockSignals(True) self.waterlvl_max.setValue(self.hydrograph.WLmin) self.waterlvl_max.blockSignals(False) # This is calculated so that trailing zeros in the altitude of the # well is not carried to the y axis labels, so that they remain a # int multiple of *WLscale*. self.hydrograph.setup_waterlvl_scale() self.hydrograph.draw_waterlvl() self.hydrograph.draw_ylabels() elif sender in [self.date_start_widget, self.date_end_widget]: self.hydrograph.set_time_scale() self.hydrograph.draw_weather() self.hydrograph.draw_figure_title() elif sender == self.dateDispFreq_spinBox: self.hydrograph.set_time_scale() self.hydrograph.setup_xticklabels() elif sender == self.page_setup_win: self.hydrograph.update_fig_size() # Implicitly call : set_margins() # draw_ylabels() # set_time_scale() # draw_figure_title self.hydrograph.draw_waterlvl() self.hydrograph.setup_legend() elif sender == self.qweather_bin: self.hydrograph.resample_bin() self.hydrograph.draw_weather() self.hydrograph.draw_ylabels() elif sender == self.time_scale_label: self.hydrograph.set_time_scale() self.hydrograph.draw_weather() else: print('No action for this widget yet.') # !!!! temporary fix until I can find a better solution !!!! # sender.blockSignals(True) if type(sender) in [QDoubleSpinBox, QSpinBox]: sender.setReadOnly(True) for i in range(10): QCoreApplication.processEvents() self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) for i in range(10): QCoreApplication.processEvents() if type(sender) in [QDoubleSpinBox, QSpinBox]: sender.setReadOnly(False) # sender.blockSignals(False) def update_graph_layout_parameter(self): # language : self.hydrograph.language = self.btn_language.language # Scales : self.hydrograph.WLmin = self.waterlvl_max.value() self.hydrograph.WLscale = self.waterlvl_scale.value() self.hydrograph.RAINscale = self.Ptot_scale.value() self.hydrograph.NZGrid = self.NZGridWL_spinBox.value() # WL Datum : self.hydrograph.WLdatum = self.datum_widget.currentIndex() # Dates : self.hydrograph.datemode = self.time_scale_label.currentText() year = self.date_start_widget.date().year() month = self.date_start_widget.date().month() self.hydrograph.TIMEmin = xldate_from_date_tuple((year, month, 1), 0) year = self.date_end_widget.date().year() month = self.date_end_widget.date().month() self.hydrograph.TIMEmax = xldate_from_date_tuple((year, month, 1), 0) self.hydrograph.date_labels_pattern = self.dateDispFreq_spinBox.value() # Page Setup : self.hydrograph.fwidth = self.page_setup_win.pageSize[0] self.hydrograph.fheight = self.page_setup_win.pageSize[1] self.hydrograph.va_ratio = self.page_setup_win.va_ratio self.hydrograph.trend_line = self.page_setup_win.isTrendLine self.hydrograph.isLegend = self.page_setup_win.isLegend self.hydrograph.isGraphTitle = self.page_setup_win.isGraphTitle self.hydrograph.set_meteo_on(self.page_setup_win.is_meteo_on) self.hydrograph.set_glue_wl_on(self.page_setup_win.is_glue_wl_on) self.hydrograph.set_mrc_wl_on(self.page_setup_win.is_mrc_wl_on) self.hydrograph.set_figframe_lw(self.page_setup_win.figframe_lw) # Weather bins : self.hydrograph.bwidth_indx = self.qweather_bin.currentIndex() def clear_hydrograph(self): """Clear the hydrograph figure to show only a blank canvas.""" self.hydrograph.clf() self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) def draw_hydrograph(self): if self.dmngr.wldataset_count() == 0: msg = 'Please import a valid water level data file first.' self.ConsoleSignal.emit('<font color=red>%s</font>' % msg) self.emit_warning(msg) return self.update_graph_layout_parameter() # Generate and Display Graph : for i in range(5): QCoreApplication.processEvents() QApplication.setOverrideCursor(Qt.WaitCursor) self.hydrograph.set_wldset(self.dmngr.get_current_wldset()) self.hydrograph.set_wxdset(self.dmngr.get_current_wxdset()) self.hydrograph.generate_hydrograph() self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) QApplication.restoreOverrideCursor() def select_save_path(self): """ Open a dialog where the user can select a file name to save the hydrograph. """ if self.wldset is None: return ffmat = "*.pdf;;*.svg;;*.png" fname = find_unique_filename(osp.join( self.save_fig_dir, 'hydrograph_%s.pdf' % self.wldset['Well'])) fname, ftype = QFileDialog.getSaveFileName( self, "Save Figure", fname, ffmat) if fname: ftype = ftype.replace('*', '') fname = fname if fname.endswith(ftype) else fname + ftype self.save_fig_dir = os.path.dirname(fname) try: self.save_figure(fname) except PermissionError: msg = "The file is in use by another application or user." QMessageBox.warning(self, 'Warning', msg, QMessageBox.Ok) self.select_save_path() def save_figure(self, fname): """Save the hydrograph figure in a file.""" self.hydrograph.generate_hydrograph() self.hydrograph.savefig(fname) # ---- Graph Layout Handlers def load_layout_isClicked(self): """Handle when the button to load the graph layout is clicked.""" if self.wldset is None: self.emit_warning( "Please import a valid water level data file first.") return layout = self.wldset.get_layout() if layout is None: self.emit_warning( "No graph layout exists for well %s." % self.wldset['Well']) else: self.load_graph_layout(layout) def load_graph_layout(self, layout): """Load the graph layout into the GUI.""" self.__updateUI = False # Scales : date = layout['TIMEmin'] date = xldate_as_tuple(date, 0) self.date_start_widget.setDate(QDate(date[0], date[1], date[2])) date = layout['TIMEmax'] date = xldate_as_tuple(date, 0) self.date_end_widget.setDate(QDate(date[0], date[1], date[2])) self.dateDispFreq_spinBox.setValue(layout['date_labels_pattern']) self.waterlvl_scale.setValue(layout['WLscale']) self.waterlvl_max.setValue(layout['WLmin']) self.NZGridWL_spinBox.setValue(layout['NZGrid']) self.Ptot_scale.setValue(layout['RAINscale']) x = ['mbgs', 'masl'].index(layout['WLdatum']) self.datum_widget.setCurrentIndex(x) self.qweather_bin.setCurrentIndex(layout['bwidth_indx']) self.time_scale_label.setCurrentIndex( self.time_scale_label.findText(layout['datemode'])) # ---- Language and colors self.btn_language.set_language(layout['language']) self.color_palette_win.load_colors() # ---- Page Setup self.page_setup_win.pageSize = (layout['fwidth'], layout['fheight']) self.page_setup_win.va_ratio = layout['va_ratio'] self.page_setup_win.isLegend = layout['legend_on'] self.page_setup_win.isGraphTitle = layout['title_on'] self.page_setup_win.isTrendLine = layout['trend_line'] self.page_setup_win.is_meteo_on = layout['meteo_on'] self.page_setup_win.is_glue_wl_on = layout['glue_wl_on'] self.page_setup_win.is_mrc_wl_on = layout['mrc_wl_on'] self.page_setup_win.figframe_lw = layout['figframe_lw'] self.page_setup_win.legend_on.set_value(layout['legend_on']) self.page_setup_win.title_on.set_value(layout['title_on']) self.page_setup_win.wltrend_on.set_value(layout['trend_line']) self.page_setup_win.meteo_on.set_value(layout['meteo_on']) self.page_setup_win.glue_wl_on.set_value(layout['glue_wl_on']) self.page_setup_win.mrc_wl_on.set_value(layout['mrc_wl_on']) self.page_setup_win.fframe_lw_widg.setValue(layout['figframe_lw']) self.page_setup_win.fwidth.setValue(layout['fwidth']) self.page_setup_win.fheight.setValue(layout['fheight']) self.page_setup_win.va_ratio_spinBox.setValue(layout['va_ratio']) # Check if Weather Dataset : if layout['wxdset'] in self.dmngr.wxdsets: self.dmngr.set_current_wxdset(layout['wxdset']) else: if self.dmngr.set_closest_wxdset() is None: self.draw_hydrograph() self.__updateUI = True def save_layout_isClicked(self): wldset = self.wldset if wldset is None: self.emit_warning( "Please import a valid water level data file first.") return layout = wldset.get_layout() if layout is not None: msg = ('A graph layout already exists for well %s.Do you want to' ' you want to replace it?') % wldset['Well'] reply = QMessageBox.question(self, 'Save Graph Layout', msg, QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: self.save_graph_layout() elif reply == QMessageBox.No: msg = "Graph layout not saved for well %s." % wldset['Well'] self.ConsoleSignal.emit('<font color=black>%s' % msg) else: self.save_graph_layout() def save_graph_layout(self): """Save the graph layout in the project hdf5 file.""" print("Saving the graph layout for well %s..." % self.wldset['Well'], end=" ") layout = {'WLmin': self.waterlvl_max.value(), 'WLscale': self.waterlvl_scale.value(), 'RAINscale': self.Ptot_scale.value(), 'fwidth': self.page_setup_win.pageSize[0], 'fheight': self.page_setup_win.pageSize[1], 'va_ratio': self.page_setup_win.va_ratio, 'NZGrid': self.NZGridWL_spinBox.value(), 'bwidth_indx': self.qweather_bin.currentIndex(), 'date_labels_pattern': self.dateDispFreq_spinBox.value(), 'datemode': self.time_scale_label.currentText()} layout['wxdset'] = None if self.wxdset is None else self.wxdset.name year = self.date_start_widget.date().year() month = self.date_start_widget.date().month() layout['TIMEmin'] = xldate_from_date_tuple((year, month, 1), 0) year = self.date_end_widget.date().year() month = self.date_end_widget.date().month() layout['TIMEmax'] = xldate_from_date_tuple((year, month, 1), 0) if self.datum_widget.currentIndex() == 0: layout['WLdatum'] = 'mbgs' else: layout['WLdatum'] = 'masl' # ---- Page Setup layout['title_on'] = bool(self.page_setup_win.isGraphTitle) layout['legend_on'] = bool(self.page_setup_win.isLegend) layout['language'] = self.btn_language.language layout['trend_line'] = bool(self.page_setup_win.isTrendLine) layout['meteo_on'] = bool(self.page_setup_win.is_meteo_on) layout['glue_wl_on'] = bool(self.page_setup_win.is_glue_wl_on) layout['mrc_wl_on'] = bool(self.page_setup_win.is_mrc_wl_on) layout['figframe_lw'] = self.page_setup_win.figframe_lw # Save the colors : cdb = ColorsReader() cdb.load_colors_db() layout['colors'] = cdb.RGB # Save the layout : self.wldset.save_layout(layout) msg = 'Layout saved successfully for well %s.' % self.wldset['Well'] self.ConsoleSignal.emit('<font color=black>%s</font>' % msg) print("done")
def createEditor(self, parent, option, index): dateedit = QDateEdit(parent) #dateedit=QDateTimeEdit(parent) dateedit.setDateRange(self.minimum, self.maximum) dateedit.setAlignment(Qt.AlignRight | Qt.AlignVCenter) dateedit.setDisplayFormat(self.format) dateedit.setCalendarPopup(True) return dateedit
def createEditor(self, parent, option, index): if (index.column() == ACTIONID and index.model().data( index, Qt.DisplayRole) == ACQUIRED): # Acquired is read-only return if index.column() == DATE: editor = QDateEdit(parent) editor.setMaximumDate(QDate.currentDate()) editor.setDisplayFormat("yyyy-MM-dd") if PYQT_VERSION_STR >= "4.1.0": editor.setCalendarPopup(True) editor.setAlignment(Qt.AlignRight | Qt.AlignVCenter) return editor else: return QSqlRelationalDelegate.createEditor(self, parent, option, index)
class HydroprintGUI(myqt.DialogWindow): ConsoleSignal = QSignal(str) def __init__(self, datamanager, parent=None): super(HydroprintGUI, self).__init__(parent, maximize=True) self.__updateUI = True # Child widgets: self.dmngr = datamanager self.dmngr.wldsetChanged.connect(self.wldset_changed) self.dmngr.wxdsetChanged.connect(self.wxdset_changed) self.page_setup_win = PageSetupWin(self) self.page_setup_win.newPageSetupSent.connect(self.layout_changed) self.color_palette_win = ColorsSetupWin(self) self.color_palette_win.newColorSetupSent.connect(self.update_colors) # Memory path variable: self.save_fig_dir = self.workdir # Generate UI: self.__initUI__() def __initUI__(self): # ---- Toolbar self.btn_save = btn_save = QToolButtonNormal(icons.get_icon('save')) btn_save.setToolTip('Save the well hydrograph') # btn_draw is usefull for debugging purposes btn_draw = QToolButtonNormal(icons.get_icon('refresh')) btn_draw.setToolTip('Force a refresh of the well hydrograph') btn_draw.hide() self.btn_load_layout = QToolButtonNormal( icons.get_icon('load_graph_config')) self.btn_load_layout.setToolTip( "<p>Load graph layout for the current water level " " datafile if it exists</p>") self.btn_load_layout.clicked.connect(self.load_layout_isClicked) self.btn_save_layout = QToolButtonNormal( icons.get_icon('save_graph_config')) self.btn_save_layout.setToolTip('Save current graph layout') self.btn_save_layout.clicked.connect(self.save_layout_isClicked) btn_bestfit_waterlvl = QToolButtonNormal(icons.get_icon('fit_y')) btn_bestfit_waterlvl.setToolTip('Best fit the water level scale') btn_bestfit_time = QToolButtonNormal(icons.get_icon('fit_x')) btn_bestfit_time.setToolTip('Best fit the time scale') self.btn_page_setup = QToolButtonNormal(icons.get_icon('page_setup')) self.btn_page_setup.setToolTip('Show the page setup window') self.btn_page_setup.clicked.connect(self.page_setup_win.show) btn_color_pick = QToolButtonNormal(icons.get_icon('color_picker')) btn_color_pick.setToolTip('<p>Show a window to setup the color palette' ' used to draw the hydrograph</p.') btn_color_pick.clicked.connect(self.color_palette_win.show) self.btn_language = LangToolButton() self.btn_language.setToolTip( "Set the language of the text shown in the graph.") self.btn_language.sig_lang_changed.connect(self.layout_changed) self.btn_language.setIconSize(icons.get_iconsize('normal')) # ---- Zoom Panel btn_zoom_out = QToolButtonSmall(icons.get_icon('zoom_out')) btn_zoom_out.setToolTip('Zoom out (ctrl + mouse-wheel-down)') btn_zoom_out.clicked.connect(self.zoom_out) btn_zoom_in = QToolButtonSmall(icons.get_icon('zoom_in')) btn_zoom_in.setToolTip('Zoom in (ctrl + mouse-wheel-up)') btn_zoom_in.clicked.connect(self.zoom_in) self.zoom_disp = QSpinBox() self.zoom_disp.setAlignment(Qt.AlignCenter) self.zoom_disp.setButtonSymbols(QAbstractSpinBox.NoButtons) self.zoom_disp.setReadOnly(True) self.zoom_disp.setSuffix(' %') self.zoom_disp.setRange(0, 9999) self.zoom_disp.setValue(100) zoom_pan = myqt.QFrameLayout() zoom_pan.setSpacing(3) zoom_pan.addWidget(btn_zoom_out, 0, 0) zoom_pan.addWidget(btn_zoom_in, 0, 1) zoom_pan.addWidget(self.zoom_disp, 0, 2) # LAYOUT : btn_list = [ btn_save, btn_draw, self.btn_load_layout, self.btn_save_layout, VSep(), btn_bestfit_waterlvl, btn_bestfit_time, VSep(), self.btn_page_setup, btn_color_pick, self.btn_language, VSep(), zoom_pan ] subgrid_toolbar = QGridLayout() toolbar_widget = QWidget() row = 0 for col, btn in enumerate(btn_list): subgrid_toolbar.addWidget(btn, row, col) subgrid_toolbar.setSpacing(5) subgrid_toolbar.setContentsMargins(0, 0, 0, 0) subgrid_toolbar.setColumnStretch(col + 1, 100) toolbar_widget.setLayout(subgrid_toolbar) # ---- LEFT PANEL # SubGrid Hydrograph Frame : self.hydrograph = hydrograph.Hydrograph() self.hydrograph_scrollarea = mplFigViewer.ImageViewer() self.hydrograph_scrollarea.zoomChanged.connect(self.zoom_disp.setValue) grid_hydrograph = QGridLayout() grid_hydrograph.addWidget(self.hydrograph_scrollarea, 0, 0) grid_hydrograph.setRowStretch(0, 500) grid_hydrograph.setColumnStretch(0, 500) grid_hydrograph.setContentsMargins(0, 0, 0, 0) # (L, T, R, B) # ASSEMBLING SubGrids : grid_layout = QGridLayout() self.grid_layout_widget = QFrame() row = 0 grid_layout.addWidget(toolbar_widget, row, 0) row += 1 grid_layout.addLayout(grid_hydrograph, row, 0) grid_layout.setContentsMargins(0, 0, 0, 0) # (L, T, R, B) grid_layout.setSpacing(5) grid_layout.setColumnStretch(0, 500) grid_layout.setRowStretch(1, 500) self.grid_layout_widget.setLayout(grid_layout) # ---- Right Panel self.tabscales = self.__init_scalesTabWidget__() self.right_panel = myqt.QFrameLayout() self.right_panel.addWidget(self.dmngr, 0, 0) self.right_panel.addWidget(self.tabscales, 1, 0) self.right_panel.setRowStretch(2, 100) self.right_panel.setSpacing(15) # ---- MAIN GRID mainGrid = QGridLayout() mainGrid.addWidget(self.grid_layout_widget, 0, 0) mainGrid.addWidget(VSep(), 0, 1) mainGrid.addWidget(self.right_panel, 0, 2) mainGrid.setContentsMargins(10, 10, 10, 10) # (L, T, R, B) mainGrid.setSpacing(15) mainGrid.setColumnStretch(0, 500) mainGrid.setColumnMinimumWidth(2, 250) self.setLayout(mainGrid) # ---- EVENTS # Toolbox Layout : btn_bestfit_waterlvl.clicked.connect(self.best_fit_waterlvl) btn_bestfit_time.clicked.connect(self.best_fit_time) btn_draw.clicked.connect(self.draw_hydrograph) btn_save.clicked.connect(self.select_save_path) # Hydrograph Layout : self.Ptot_scale.valueChanged.connect(self.layout_changed) self.qweather_bin.currentIndexChanged.connect(self.layout_changed) # ---- Init Image self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) def __init_scalesTabWidget__(self): class QRowLayout(QGridLayout): def __init__(self, items, parent=None): super(QRowLayout, self).__init__(parent) for col, item in enumerate(items): self.addWidget(item, 0, col) self.setContentsMargins(0, 0, 0, 0) self.setColumnStretch(0, 100) # ---- Time axis properties # Generate the widgets : self.date_start_widget = QDateEdit() self.date_start_widget.setDisplayFormat('01 / MM / yyyy') self.date_start_widget.setAlignment(Qt.AlignCenter) self.date_start_widget.dateChanged.connect(self.layout_changed) self.date_end_widget = QDateEdit() self.date_end_widget.setDisplayFormat('01 / MM / yyyy') self.date_end_widget.setAlignment(Qt.AlignCenter) self.date_end_widget.dateChanged.connect(self.layout_changed) self.time_scale_label = QComboBox() self.time_scale_label.setEditable(False) self.time_scale_label.setInsertPolicy(QComboBox.NoInsert) self.time_scale_label.addItems(['Month', 'Year']) self.time_scale_label.setCurrentIndex(0) self.time_scale_label.currentIndexChanged.connect(self.layout_changed) self.dateDispFreq_spinBox = QSpinBox() self.dateDispFreq_spinBox.setSingleStep(1) self.dateDispFreq_spinBox.setMinimum(1) self.dateDispFreq_spinBox.setMaximum(100) self.dateDispFreq_spinBox.setValue(self.hydrograph.date_labels_pattern) self.dateDispFreq_spinBox.setAlignment(Qt.AlignCenter) self.dateDispFreq_spinBox.setKeyboardTracking(False) self.dateDispFreq_spinBox.valueChanged.connect(self.layout_changed) # Setting up the layout : widget_time_scale = QFrame() widget_time_scale.setFrameStyle(0) grid_time_scale = QGridLayout() GRID = [[QLabel('From :'), self.date_start_widget], [QLabel('To :'), self.date_end_widget], [QLabel('Scale :'), self.time_scale_label], [QLabel('Date Disp. Pattern:'), self.dateDispFreq_spinBox]] for i, ROW in enumerate(GRID): grid_time_scale.addLayout(QRowLayout(ROW), i, 1) grid_time_scale.setVerticalSpacing(5) grid_time_scale.setContentsMargins(10, 10, 10, 10) widget_time_scale.setLayout(grid_time_scale) # ----- Water level axis properties # Widget : self.waterlvl_scale = QDoubleSpinBox() self.waterlvl_scale.setSingleStep(0.05) self.waterlvl_scale.setMinimum(0.05) self.waterlvl_scale.setSuffix(' m') self.waterlvl_scale.setAlignment(Qt.AlignCenter) self.waterlvl_scale.setKeyboardTracking(False) self.waterlvl_scale.valueChanged.connect(self.layout_changed) self.waterlvl_scale.setFixedWidth(100) self.waterlvl_max = QDoubleSpinBox() self.waterlvl_max.setSingleStep(0.1) self.waterlvl_max.setSuffix(' m') self.waterlvl_max.setAlignment(Qt.AlignCenter) self.waterlvl_max.setMinimum(-1000) self.waterlvl_max.setMaximum(1000) self.waterlvl_max.setKeyboardTracking(False) self.waterlvl_max.valueChanged.connect(self.layout_changed) self.waterlvl_max.setFixedWidth(100) self.NZGridWL_spinBox = QSpinBox() self.NZGridWL_spinBox.setSingleStep(1) self.NZGridWL_spinBox.setMinimum(1) self.NZGridWL_spinBox.setMaximum(50) self.NZGridWL_spinBox.setValue(self.hydrograph.NZGrid) self.NZGridWL_spinBox.setAlignment(Qt.AlignCenter) self.NZGridWL_spinBox.setKeyboardTracking(False) self.NZGridWL_spinBox.valueChanged.connect(self.layout_changed) self.NZGridWL_spinBox.setFixedWidth(100) self.datum_widget = QComboBox() self.datum_widget.addItems(['Ground Surface', 'Sea Level']) self.datum_widget.currentIndexChanged.connect(self.layout_changed) # Layout : subgrid_WLScale = QGridLayout() GRID = [[QLabel('Minimum :'), self.waterlvl_max], [QLabel('Scale :'), self.waterlvl_scale], [QLabel('Grid Divisions :'), self.NZGridWL_spinBox], [QLabel('Datum :'), self.datum_widget]] for i, ROW in enumerate(GRID): subgrid_WLScale.addLayout(QRowLayout(ROW), i, 1) subgrid_WLScale.setVerticalSpacing(5) subgrid_WLScale.setContentsMargins(10, 10, 10, 10) # (L, T, R, B) WLScale_widget = QFrame() WLScale_widget.setFrameStyle(0) WLScale_widget.setLayout(subgrid_WLScale) # ---- Weather Axis # Widgets : self.Ptot_scale = QSpinBox() self.Ptot_scale.setSingleStep(5) self.Ptot_scale.setMinimum(5) self.Ptot_scale.setMaximum(500) self.Ptot_scale.setValue(20) self.Ptot_scale.setSuffix(' mm') self.Ptot_scale.setAlignment(Qt.AlignCenter) self.qweather_bin = QComboBox() self.qweather_bin.setEditable(False) self.qweather_bin.setInsertPolicy(QComboBox.NoInsert) self.qweather_bin.addItems(['day', 'week', 'month']) self.qweather_bin.setCurrentIndex(1) # Layout : layout = QGridLayout() GRID = [[QLabel('Precip. Scale :'), self.Ptot_scale], [QLabel('Resampling :'), self.qweather_bin]] for i, row in enumerate(GRID): layout.addLayout(QRowLayout(row), i, 1) layout.setVerticalSpacing(5) layout.setContentsMargins(10, 10, 10, 10) # (L,T,R,B) layout.setRowStretch(i + 1, 100) widget_weather_scale = QFrame() widget_weather_scale.setFrameStyle(0) widget_weather_scale.setLayout(layout) # ---- ASSEMBLING TABS tabscales = QTabWidget() tabscales.addTab(widget_time_scale, 'Time') tabscales.addTab(WLScale_widget, 'Water Level') tabscales.addTab(widget_weather_scale, 'Weather') return tabscales @property def workdir(self): return self.dmngr.workdir # ---- Utilities def zoom_in(self): self.hydrograph_scrollarea.zoomIn() def zoom_out(self): self.hydrograph_scrollarea.zoomOut() def update_colors(self): self.hydrograph.update_colors() self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) # ---- Datasets Handlers @property def wldset(self): return self.dmngr.get_current_wldset() @property def wxdset(self): return self.dmngr.get_current_wxdset() def wldset_changed(self): """Handle when the water level dataset of the datamanager changes.""" if self.wldset is None: self.clear_hydrograph() return else: wldset = self.wldset self.hydrograph.set_wldset(wldset) self.hydrograph.gluedf = self.wldset.get_glue_at(-1) # Load the manual measurements. fname = os.path.join(self.workdir, "Water Levels", 'waterlvl_manual_measurements') tmeas, wlmeas = load_waterlvl_measures(fname, wldset['Well']) wldset.set_wlmeas(tmeas, wlmeas) # Setup the layout of the hydrograph. layout = wldset.get_layout() if layout is not None: msg = 'Loading existing graph layout for well %s.' % wldset['Well'] print(msg) self.ConsoleSignal.emit('<font color=black>%s</font>' % msg) self.load_graph_layout(layout) else: print('No graph layout exists for well %s.' % wldset['Well']) # Fit Water Level in Layout : self.__updateUI = False self.best_fit_waterlvl() self.best_fit_time() self.dmngr.set_closest_wxdset() self.__updateUI = True def wxdset_changed(self): """Handle when the weather dataset of the datamanager changes.""" if self.wldset is None: self.clear_hydrograph() else: self.hydrograph.set_wxdset(self.wxdset) QCoreApplication.processEvents() self.draw_hydrograph() # ---- Draw Hydrograph Handlers def best_fit_waterlvl(self): wldset = self.dmngr.get_current_wldset() if wldset is not None: WLscale, WLmin = self.hydrograph.best_fit_waterlvl() self.waterlvl_scale.setValue(WLscale) self.waterlvl_max.setValue(WLmin) def best_fit_time(self): wldset = self.dmngr.get_current_wldset() if wldset is not None: date0, date1 = self.hydrograph.best_fit_time(wldset['Time']) self.date_start_widget.setDate(QDate(date0[0], date0[1], date0[2])) self.date_end_widget.setDate(QDate(date1[0], date1[1], date1[2])) @QSlot() def mrc_wl_changed(self): """ Force a redraw of the MRC water levels after the results have changed for the dataset. """ self.hydrograph.draw_mrc_wl() self.hydrograph.setup_legend() self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) @QSlot(GLUEDataFrameBase) def glue_wl_changed(self, gluedf): """ Force a redraw of the GLUE water levels after the results have changed for the dataset. """ self.hydrograph.set_gluedf(gluedf) self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) def layout_changed(self): """ When an element of the graph layout is changed in the UI. """ if self.__updateUI is False: return self.update_graph_layout_parameter() if self.hydrograph.isHydrographExists is False: return sender = self.sender() if sender == self.btn_language: self.hydrograph.draw_ylabels() self.hydrograph.setup_xticklabels() self.hydrograph.setup_legend() elif sender in [self.waterlvl_max, self.waterlvl_scale]: self.hydrograph.setup_waterlvl_scale() self.hydrograph.draw_ylabels() elif sender == self.NZGridWL_spinBox: self.hydrograph.setup_waterlvl_scale() self.hydrograph.update_precip_scale() self.hydrograph.draw_ylabels() elif sender == self.Ptot_scale: self.hydrograph.update_precip_scale() self.hydrograph.draw_ylabels() elif sender == self.datum_widget: yoffset = int(self.wldset['Elevation'] / self.hydrograph.WLscale) yoffset *= self.hydrograph.WLscale self.hydrograph.WLmin = (yoffset - self.hydrograph.WLmin) self.waterlvl_max.blockSignals(True) self.waterlvl_max.setValue(self.hydrograph.WLmin) self.waterlvl_max.blockSignals(False) # This is calculated so that trailing zeros in the altitude of the # well is not carried to the y axis labels, so that they remain a # int multiple of *WLscale*. self.hydrograph.setup_waterlvl_scale() self.hydrograph.draw_waterlvl() self.hydrograph.draw_ylabels() elif sender in [self.date_start_widget, self.date_end_widget]: self.hydrograph.set_time_scale() self.hydrograph.draw_weather() self.hydrograph.draw_figure_title() elif sender == self.dateDispFreq_spinBox: self.hydrograph.set_time_scale() self.hydrograph.setup_xticklabels() elif sender == self.page_setup_win: self.hydrograph.update_fig_size() # Implicitly call : set_margins() # draw_ylabels() # set_time_scale() # draw_figure_title self.hydrograph.draw_waterlvl() self.hydrograph.setup_legend() elif sender == self.qweather_bin: self.hydrograph.resample_bin() self.hydrograph.draw_weather() self.hydrograph.draw_ylabels() elif sender == self.time_scale_label: self.hydrograph.set_time_scale() self.hydrograph.draw_weather() else: print('No action for this widget yet.') # !!!! temporary fix until I can find a better solution !!!! # sender.blockSignals(True) if type(sender) in [QDoubleSpinBox, QSpinBox]: sender.setReadOnly(True) for i in range(10): QCoreApplication.processEvents() self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) for i in range(10): QCoreApplication.processEvents() if type(sender) in [QDoubleSpinBox, QSpinBox]: sender.setReadOnly(False) # sender.blockSignals(False) def update_graph_layout_parameter(self): # language : self.hydrograph.language = self.btn_language.language # Scales : self.hydrograph.WLmin = self.waterlvl_max.value() self.hydrograph.WLscale = self.waterlvl_scale.value() self.hydrograph.RAINscale = self.Ptot_scale.value() self.hydrograph.NZGrid = self.NZGridWL_spinBox.value() # WL Datum : self.hydrograph.WLdatum = self.datum_widget.currentIndex() # Dates : self.hydrograph.datemode = self.time_scale_label.currentText() year = self.date_start_widget.date().year() month = self.date_start_widget.date().month() self.hydrograph.TIMEmin = xldate_from_date_tuple((year, month, 1), 0) year = self.date_end_widget.date().year() month = self.date_end_widget.date().month() self.hydrograph.TIMEmax = xldate_from_date_tuple((year, month, 1), 0) self.hydrograph.date_labels_pattern = self.dateDispFreq_spinBox.value() # Page Setup : self.hydrograph.fwidth = self.page_setup_win.pageSize[0] self.hydrograph.fheight = self.page_setup_win.pageSize[1] self.hydrograph.va_ratio = self.page_setup_win.va_ratio self.hydrograph.trend_line = self.page_setup_win.isTrendLine self.hydrograph.isLegend = self.page_setup_win.isLegend self.hydrograph.isGraphTitle = self.page_setup_win.isGraphTitle self.hydrograph.set_meteo_on(self.page_setup_win.is_meteo_on) self.hydrograph.set_glue_wl_on(self.page_setup_win.is_glue_wl_on) self.hydrograph.set_mrc_wl_on(self.page_setup_win.is_mrc_wl_on) self.hydrograph.set_figframe_lw(self.page_setup_win.figframe_lw) # Weather bins : self.hydrograph.bwidth_indx = self.qweather_bin.currentIndex() def clear_hydrograph(self): """Clear the hydrograph figure to show only a blank canvas.""" self.hydrograph.clf() self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) def draw_hydrograph(self): if self.dmngr.wldataset_count() == 0: msg = 'Please import a valid water level data file first.' self.ConsoleSignal.emit('<font color=red>%s</font>' % msg) self.emit_warning(msg) return self.update_graph_layout_parameter() # Generate and Display Graph : for i in range(5): QCoreApplication.processEvents() QApplication.setOverrideCursor(Qt.WaitCursor) self.hydrograph.set_wldset(self.dmngr.get_current_wldset()) self.hydrograph.set_wxdset(self.dmngr.get_current_wxdset()) self.hydrograph.generate_hydrograph() self.hydrograph_scrollarea.load_mpl_figure(self.hydrograph) QApplication.restoreOverrideCursor() def select_save_path(self): """ Open a dialog where the user can select a file name to save the hydrograph. """ if self.wldset is None: return ffmat = "*.pdf;;*.svg;;*.png" fname = find_unique_filename( osp.join(self.save_fig_dir, 'hydrograph_%s.pdf' % self.wldset['Well'])) fname, ftype = QFileDialog.getSaveFileName(self, "Save Figure", fname, ffmat) if fname: ftype = ftype.replace('*', '') fname = fname if fname.endswith(ftype) else fname + ftype self.save_fig_dir = os.path.dirname(fname) try: self.save_figure(fname) except PermissionError: msg = "The file is in use by another application or user." QMessageBox.warning(self, 'Warning', msg, QMessageBox.Ok) self.select_save_path() def save_figure(self, fname): """Save the hydrograph figure in a file.""" self.hydrograph.generate_hydrograph() self.hydrograph.savefig(fname) # ---- Graph Layout Handlers def load_layout_isClicked(self): """Handle when the button to load the graph layout is clicked.""" if self.wldset is None: self.emit_warning( "Please import a valid water level data file first.") return layout = self.wldset.get_layout() if layout is None: self.emit_warning("No graph layout exists for well %s." % self.wldset['Well']) else: self.load_graph_layout(layout) def load_graph_layout(self, layout): """Load the graph layout into the GUI.""" self.__updateUI = False # Scales : date = layout['TIMEmin'] date = xldate_as_tuple(date, 0) self.date_start_widget.setDate(QDate(date[0], date[1], date[2])) date = layout['TIMEmax'] date = xldate_as_tuple(date, 0) self.date_end_widget.setDate(QDate(date[0], date[1], date[2])) self.dateDispFreq_spinBox.setValue(layout['date_labels_pattern']) self.waterlvl_scale.setValue(layout['WLscale']) self.waterlvl_max.setValue(layout['WLmin']) self.NZGridWL_spinBox.setValue(layout['NZGrid']) self.Ptot_scale.setValue(layout['RAINscale']) x = ['mbgs', 'masl'].index(layout['WLdatum']) self.datum_widget.setCurrentIndex(x) self.qweather_bin.setCurrentIndex(layout['bwidth_indx']) self.time_scale_label.setCurrentIndex( self.time_scale_label.findText(layout['datemode'])) # ---- Language and colors self.btn_language.set_language(layout['language']) self.color_palette_win.load_colors() # ---- Page Setup self.page_setup_win.pageSize = (layout['fwidth'], layout['fheight']) self.page_setup_win.va_ratio = layout['va_ratio'] self.page_setup_win.isLegend = layout['legend_on'] self.page_setup_win.isGraphTitle = layout['title_on'] self.page_setup_win.isTrendLine = layout['trend_line'] self.page_setup_win.is_meteo_on = layout['meteo_on'] self.page_setup_win.is_glue_wl_on = layout['glue_wl_on'] self.page_setup_win.is_mrc_wl_on = layout['mrc_wl_on'] self.page_setup_win.figframe_lw = layout['figframe_lw'] self.page_setup_win.legend_on.set_value(layout['legend_on']) self.page_setup_win.title_on.set_value(layout['title_on']) self.page_setup_win.wltrend_on.set_value(layout['trend_line']) self.page_setup_win.meteo_on.set_value(layout['meteo_on']) self.page_setup_win.glue_wl_on.set_value(layout['glue_wl_on']) self.page_setup_win.mrc_wl_on.set_value(layout['mrc_wl_on']) self.page_setup_win.fframe_lw_widg.setValue(layout['figframe_lw']) self.page_setup_win.fwidth.setValue(layout['fwidth']) self.page_setup_win.fheight.setValue(layout['fheight']) self.page_setup_win.va_ratio_spinBox.setValue(layout['va_ratio']) # Check if Weather Dataset : if layout['wxdset'] in self.dmngr.wxdsets: self.dmngr.set_current_wxdset(layout['wxdset']) else: self.dmngr.set_closest_wxdset() self.__updateUI = True def save_layout_isClicked(self): wldset = self.wldset if wldset is None: self.emit_warning( "Please import a valid water level data file first.") return layout = wldset.get_layout() if layout is not None: msg = ('A graph layout already exists for well %s.Do you want to' ' you want to replace it?') % wldset['Well'] reply = QMessageBox.question(self, 'Save Graph Layout', msg, QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: self.save_graph_layout() elif reply == QMessageBox.No: msg = "Graph layout not saved for well %s." % wldset['Well'] self.ConsoleSignal.emit('<font color=black>%s' % msg) else: self.save_graph_layout() def save_graph_layout(self): """Save the graph layout in the project hdf5 file.""" print("Saving the graph layout for well %s..." % self.wldset['Well'], end=" ") layout = { 'WLmin': self.waterlvl_max.value(), 'WLscale': self.waterlvl_scale.value(), 'RAINscale': self.Ptot_scale.value(), 'fwidth': self.page_setup_win.pageSize[0], 'fheight': self.page_setup_win.pageSize[1], 'va_ratio': self.page_setup_win.va_ratio, 'NZGrid': self.NZGridWL_spinBox.value(), 'bwidth_indx': self.qweather_bin.currentIndex(), 'date_labels_pattern': self.dateDispFreq_spinBox.value(), 'datemode': self.time_scale_label.currentText() } layout['wxdset'] = None if self.wxdset is None else self.wxdset.name year = self.date_start_widget.date().year() month = self.date_start_widget.date().month() layout['TIMEmin'] = xldate_from_date_tuple((year, month, 1), 0) year = self.date_end_widget.date().year() month = self.date_end_widget.date().month() layout['TIMEmax'] = xldate_from_date_tuple((year, month, 1), 0) if self.datum_widget.currentIndex() == 0: layout['WLdatum'] = 'mbgs' else: layout['WLdatum'] = 'masl' # ---- Page Setup layout['title_on'] = bool(self.page_setup_win.isGraphTitle) layout['legend_on'] = bool(self.page_setup_win.isLegend) layout['language'] = self.btn_language.language layout['trend_line'] = bool(self.page_setup_win.isTrendLine) layout['meteo_on'] = bool(self.page_setup_win.is_meteo_on) layout['glue_wl_on'] = bool(self.page_setup_win.is_glue_wl_on) layout['mrc_wl_on'] = bool(self.page_setup_win.is_mrc_wl_on) layout['figframe_lw'] = self.page_setup_win.figframe_lw # Save the colors : cdb = ColorsReader() cdb.load_colors_db() layout['colors'] = cdb.RGB # Save the layout : self.wldset.save_layout(layout) msg = 'Layout saved successfully for well %s.' % self.wldset['Well'] self.ConsoleSignal.emit('<font color=black>%s</font>' % msg) print("done")
class TransactionWindow(BaseWindow): def __init__(self, mainWindows=None): super().__init__(mainWindows, "Transações", 0.25, 0, 0.5, 0.55, "budget.png") self.createLayout() def addTransaction(self): dialog = AddTransDialog(self, "Adicionar Transação: ") result = dialog.exec_() if result: dialog.process(None) def addTransfer(self): dialog = AddTransfer(self) result = dialog.exec_() if result: dialog.process() self.mainWindow.loadInfo() def createLayout(self): base = QWidget() layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) monthBox = QHBoxLayout() self.date = QDateEdit(QDate.currentDate()) self.date.setCalendarPopup(True) self.date.setDisplayFormat("MMMM yyyy") self.date.setAlignment(Qt.AlignCenter) def dateChanged(): msg = "Exibindo transações de %s" % ( self.date.date().toString("MM-yyyy")) self.mainWindow.showMessage(msg) self.mainWindow.loadInfo() self.date.dateChanged.connect(dateChanged) left = QToolButton() left.setArrowType(Qt.LeftArrow) left.clicked.connect( lambda: self.date.setDate(self.date.date().addMonths(-1))) right = QToolButton() right.setArrowType(Qt.RightArrow) right.clicked.connect( lambda: self.date.setDate(self.date.date().addMonths(1))) monthBox.addStretch(1) monthBox.addWidget(left) monthBox.addWidget(self.date, 1) monthBox.addWidget(right) monthBox.addStretch(1) self.view = Tree(6) self.view.setResizeColumn(2) self.view.setColumnWidth(0, 75) self.view.setColumnWidth(1, 175) self.view.setColumnWidth(2, 200) self.view.setColumnWidth(3, 100) self.view.setColumnWidth(5, 10) self.view.itemDoubleClicked.connect(self.editItem) layout.addLayout(monthBox) layout.addWidget(self.view, 1) base.setLayout(layout) self.setWidget(base) self.setFocusPolicy(Qt.StrongFocus) def createMenusAndToolbar(self): add = self.mainWindow.operationsMenu.addAction("Adicionar Transação") add.setIcon(Icon("money.png")) add.triggered.connect(self.addTransaction) addTransfer = self.mainWindow.operationsMenu.addAction( "Adicionar Transferência") addTransfer.setIcon(Icon("transfer.png")) addTransfer.triggered.connect(self.addTransfer) delete = self.mainWindow.operationsMenu.addAction("Apagar Transações") delete.setIcon(Icon("del-trans.png")) delete.triggered.connect(self.deleteItems) toolbar = QToolBar("Operações de Transação") toolbar.addAction(add) toolbar.addAction(addTransfer) toolbar.addAction(delete) self.mainWindow.addToolBar(toolbar) def deleteItem(self, item): date = item.parent().data(0, Qt.DisplayRole) result = QMessageBox.question( self, "Apagar Transação", "Deseja realmente apagar a transação:\n\n" + ">%s\n" % date.toString("dd/MM/yyyy") + ">%s\n" % item.text(1) + ">Conta:\t\t%s\n" % item.text(3) + ">Categoria:\t%s\n" % item.text(2) + ">Valor:\t\t%s" % item.text(4)) if result == QMessageBox.Yes: DATABASE.delTransaction(item.ident) self.mainWindow.showMessage("Transação Apagada.") self.mainWindow.loadInfo() def deleteItems(self): items = self.view.getChecked(0) if items: result = QMessageBox.question( self, "Apagar Transações", "Deseja realmente apagar as %d transações selecionadas?" % len(items)) if result == QMessageBox.Yes: for item in items: DATABASE.delTransaction(item.ident) self.mainWindow.showMessage("%d transações Apagadas." % len(items)) self.mainWindow.loadInfo() def editItem(self, item, column, invoice=False): if item.parent() or invoice: dialog = AddTransDialog(self, "Editar Transação: ", item) result = dialog.exec_() if result: dialog.process(item) def loadInfo(self): self.view.clear() self.view.setHeaderLabels(COLUMNS) for item in DATABASE.getTransactions(self.date.date()): itemDate = QDate(item[3], item[2], item[1]) topDate = self.view.getTopItem(itemDate) if topDate: reg = TreeItem(topDate, '') else: top = TreeItem(self.view, '') top.setData(0, Qt.DisplayRole, itemDate) reg = TreeItem(top, '') reg.setIdent(item[0]) reg.setCheckState(0, Qt.Unchecked) reg.setText(1, item[4]) reg.setText(2, item[5]) reg.setTextAlignment(2, Qt.AlignCenter) reg.setText(3, item[7]) reg.setTextAlignment(3, Qt.AlignCenter) reg.setText(4, "R$ %.2f " % item[8]) reg.setTextAlignment(4, Qt.AlignRight) delBtn = DeleteButton(treeItem=reg) delBtn.clicked.connect(self.deleteItem) self.view.setItemWidget(reg, 5, delBtn) self.view.resizeColumnToContents(0) self.view.expandAll() self.view.sortItems(0, Qt.DescendingOrder)
class PaymentDlg(QDialog): def __init__(self, parent=None): super(PaymentDlg, self).__init__(parent) forenameLabel = QLabel("&Forename:") self.forenameLineEdit = QLineEdit() forenameLabel.setBuddy(self.forenameLineEdit) surnameLabel = QLabel("&Surname:") self.surnameLineEdit = QLineEdit() surnameLabel.setBuddy(self.surnameLineEdit) invoiceLabel = QLabel("&Invoice No.:") self.invoiceSpinBox = QSpinBox() invoiceLabel.setBuddy(self.invoiceSpinBox) self.invoiceSpinBox.setRange(1, 10000000) self.invoiceSpinBox.setValue(100000) self.invoiceSpinBox.setAlignment(Qt.AlignRight|Qt.AlignVCenter) amountLabel = QLabel("&Amount:") self.amountSpinBox = QDoubleSpinBox() amountLabel.setBuddy(self.amountSpinBox) self.amountSpinBox.setRange(0, 5000.0) self.amountSpinBox.setPrefix("$ ") self.amountSpinBox.setAlignment(Qt.AlignRight|Qt.AlignVCenter) self.paidCheckBox = QCheckBox("&Paid") checkNumLabel = QLabel("Check &No.:") self.checkNumLineEdit = QLineEdit() checkNumLabel.setBuddy(self.checkNumLineEdit) bankLabel = QLabel("&Bank:") self.bankLineEdit = QLineEdit() bankLabel.setBuddy(self.bankLineEdit) accountNumLabel = QLabel("Acco&unt No.:") self.accountNumLineEdit = QLineEdit() accountNumLabel.setBuddy(self.accountNumLineEdit) sortCodeLabel = QLabel("Sort &Code:") self.sortCodeLineEdit = QLineEdit() sortCodeLabel.setBuddy(self.sortCodeLineEdit) creditCardLabel = QLabel("&Number:") self.creditCardLineEdit = QLineEdit() creditCardLabel.setBuddy(self.creditCardLineEdit) validFromLabel = QLabel("&Valid From:") self.validFromDateEdit = QDateEdit() validFromLabel.setBuddy(self.validFromDateEdit) self.validFromDateEdit.setDisplayFormat("MMM yyyy") self.validFromDateEdit.setAlignment(Qt.AlignRight|Qt.AlignVCenter) expiryLabel = QLabel("E&xpiry Date:") self.expiryDateEdit = QDateEdit() expiryLabel.setBuddy(self.expiryDateEdit) self.expiryDateEdit.setDisplayFormat("MMM yyyy") self.expiryDateEdit.setAlignment(Qt.AlignRight|Qt.AlignVCenter) self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok| QDialogButtonBox.Cancel) tabWidget = QTabWidget() cashWidget = QWidget() cashLayout = QHBoxLayout() cashLayout.addWidget(self.paidCheckBox) cashWidget.setLayout(cashLayout) tabWidget.addTab(cashWidget, "Cas&h") checkWidget = QWidget() checkLayout = QGridLayout() checkLayout.addWidget(checkNumLabel, 0, 0) checkLayout.addWidget(self.checkNumLineEdit, 0, 1) checkLayout.addWidget(bankLabel, 0, 2) checkLayout.addWidget(self.bankLineEdit, 0, 3) checkLayout.addWidget(accountNumLabel, 1, 0) checkLayout.addWidget(self.accountNumLineEdit, 1, 1) checkLayout.addWidget(sortCodeLabel, 1, 2) checkLayout.addWidget(self.sortCodeLineEdit, 1, 3) checkWidget.setLayout(checkLayout) tabWidget.addTab(checkWidget, "Chec&k") creditWidget = QWidget() creditLayout = QGridLayout() creditLayout.addWidget(creditCardLabel, 0, 0) creditLayout.addWidget(self.creditCardLineEdit, 0, 1, 1, 3) creditLayout.addWidget(validFromLabel, 1, 0) creditLayout.addWidget(self.validFromDateEdit, 1, 1) creditLayout.addWidget(expiryLabel, 1, 2) creditLayout.addWidget(self.expiryDateEdit, 1, 3) creditWidget.setLayout(creditLayout) tabWidget.addTab(creditWidget, "Credit Car&d") gridLayout = QGridLayout() gridLayout.addWidget(forenameLabel, 0, 0) gridLayout.addWidget(self.forenameLineEdit, 0, 1) gridLayout.addWidget(surnameLabel, 0, 2) gridLayout.addWidget(self.surnameLineEdit, 0, 3) gridLayout.addWidget(invoiceLabel, 1, 0) gridLayout.addWidget(self.invoiceSpinBox, 1, 1) gridLayout.addWidget(amountLabel, 1, 2) gridLayout.addWidget(self.amountSpinBox, 1, 3) layout = QVBoxLayout() layout.addLayout(gridLayout) layout.addWidget(tabWidget) layout.addWidget(self.buttonBox) self.setLayout(layout) for lineEdit in (self.forenameLineEdit, self.surnameLineEdit, self.checkNumLineEdit, self.accountNumLineEdit, self.bankLineEdit, self.sortCodeLineEdit, self.creditCardLineEdit): lineEdit.textEdited.connect(self.updateUi) for dateEdit in (self.validFromDateEdit, self.expiryDateEdit): dateEdit.dateChanged.connect(self.updateUi) self.paidCheckBox.clicked.connect(self.updateUi) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.updateUi() self.setWindowTitle("Payment Form") def updateUi(self): today = QDate.currentDate() enable = (self.forenameLineEdit.text() and self.surnameLineEdit.text()) if enable: enable = (self.paidCheckBox.isChecked() or (self.checkNumLineEdit.text() and self.accountNumLineEdit.text() and self.bankLineEdit.text() and self.sortCodeLineEdit.text()) or (self.creditCardLineEdit.text() and self.validFromDateEdit.date() <= today and self.expiryDateEdit.date() >= today)) self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(bool(enable))
class MainWindow(QWidget): articleInfoUpdate = pyqtSignal() entityUpdate = pyqtSignal() crawlerUpdate = pyqtSignal() def __init__(self): super(MainWindow, self).__init__() self.initUI() self.articleInfoUpdate.connect(self.updateArticleInfo) self.entityUpdate.connect(self.updateEntityList) def initUI(self): self.setGeometry(0, 0, 500, 700) self.center() self.setWindowTitle('PView') mainLayout = QVBoxLayout() self.createArticleInfoBox() self.createViewArticleBox() self.createEntityBox() self.createReportBox() self.createDatabaseBox() mainLayout.addWidget(self.infoBox) mainLayout.addWidget(self.viewArticleBox) mainLayout.addWidget(self.entityBox) mainLayout.addWidget(self.raportBox) mainLayout.addWidget(self.databaseBox) self.setLayout(mainLayout) self.show() def createArticleInfoBox(self): self.articleCount = self.selectCountArticles() entityCount = self.selectCountEntities() associationsCount = self.selectCountAssociations() classifiedCount = self.selectCountClassifiedAssociations() label = "Number of articles: " + str(self.articleCount) self.articleCountLabel = QLabel(label) label = "Number of entities: " + str(entityCount) self.entitiesCountLabel = QLabel(label) label = "Number of associations: " + str(associationsCount) self.associationsCountLabel = QLabel(label) label = "Number of classified associations: " + str(classifiedCount) self.classifiedCountLabel = QLabel(label) layout = QVBoxLayout() layout.addWidget(self.articleCountLabel) layout.addWidget(self.entitiesCountLabel) layout.addWidget(self.associationsCountLabel) layout.addWidget(self.classifiedCountLabel) self.infoBox = QGroupBox("Statistics") self.infoBox.setLayout(layout) def createCrawlerBox(self): self.crawlButton = QPushButton("Crawl") self.crawlButton.setFocusPolicy(Qt.NoFocus) self.websiteList = QComboBox() self.websiteList.addItem("HotNews") layout = QGridLayout() layout.addWidget(self.websiteList, 0, 0, 1, 1) layout.addWidget(self.crawlButton, 0, 1, 1, 1) layout.setColumnStretch(0, 1) layout.setColumnStretch(1, 1) self.crawlerBox = QGroupBox("Crawler") self.crawlerBox.setLayout(layout) def createViewArticleBox(self): self.articleNumberLineEdit = QLineEdit("") self.articleNumberLineEdit.setAlignment(Qt.AlignHCenter) self.viewArticleButton = QPushButton("Open") self.viewArticleButton.clicked.connect(self.viewArticle) layout = QGridLayout() layout.addWidget(self.articleNumberLineEdit, 0, 0, 1, 1) layout.addWidget(self.viewArticleButton, 0, 1, 1, 1) layout.setColumnStretch(0, 1) layout.setColumnStretch(1, 1) self.viewArticleBox = QGroupBox("View Article") self.viewArticleBox.setLayout(layout) def createReportBox(self): minDate, maxDate = self.selectMinAndMaxDate() minDate = QDate(minDate.year, minDate.month, minDate.day) maxDate = QDate(maxDate.year, maxDate.month, maxDate.day) self.fromDateEdit = QDateEdit() self.fromDateEdit.setDate(minDate) self.fromDateEdit.setDisplayFormat('d MMM yyyy') self.fromDateEdit.setAlignment(Qt.AlignHCenter) self.toDateEdit = QDateEdit() self.toDateEdit.setDate(maxDate) self.toDateEdit.setDisplayFormat('d MMM yyyy') self.toDateEdit.setAlignment(Qt.AlignHCenter) self.reportTypeComboBox = QComboBox() for item in reportTypes: self.reportTypeComboBox.addItem(item) monthlyButton = QPushButton("View") monthlyButton.clicked.connect(self.createReport) layout = QGridLayout() layout.addWidget(self.fromDateEdit, 0, 0, 1, 1) layout.addWidget(self.toDateEdit, 0, 1, 1, 1) layout.addWidget(self.reportTypeComboBox, 1, 0, 1, 1) layout.addWidget(monthlyButton, 1, 1, 1, 1) layout.setColumnStretch(0, 1) layout.setColumnStretch(1, 1) self.raportBox = QGroupBox("Charts") self.raportBox.setLayout(layout) def createEntityBox(self): rows = self.selectCountEntities() self.entityList = QListWidget() entities = self.selectAllEntities() for entity in entities: self.doAssociationsForEntity(entity[1]) self.entityList.addItem(entity[1]) addButton = QPushButton("Add") addButton.clicked.connect(self.addEntity) removeButton = QPushButton("Delete") removeButton.clicked.connect(self.removeEntity) self.addEntityLineEdit = QLineEdit("") viewArticlesButton = QPushButton("View articles") viewArticlesButton.clicked.connect(self.viewArticleByEntity) self.algorithmComboBox = QComboBox() for key in classifiers.keys(): self.algorithmComboBox.addItem(key) classifyButton = QPushButton("Classify") classifyButton.clicked.connect(self.classifyAllAssociations) layout = QGridLayout() layout.addWidget(self.entityList, 0, 0, 1, 4) layout.addWidget(self.addEntityLineEdit, 1, 0, 1, 2) layout.addWidget(addButton, 1, 2, 1, 1) layout.addWidget(removeButton, 1, 3, 1, 1) layout.addWidget(viewArticlesButton, 2, 0, 1, 4) layout.addWidget(self.algorithmComboBox, 3, 0, 1, 2) layout.addWidget(classifyButton, 3, 2, 1, 2) layout.setColumnStretch(0, 1) layout.setColumnStretch(1, 1) layout.setColumnStretch(2, 1) layout.setColumnStretch(3, 1) self.entityBox = QGroupBox("Entities") self.entityBox.setLayout(layout) def createDatabaseBox(self): deleteClassificationsButton = QPushButton("Remove all classifications") deleteClassificationsButton.clicked.connect(self.clearAllCalculatedPolarities) deleteEntitiesButton = QPushButton("Remove all entities") deleteEntitiesButton.clicked.connect(self.deleteAllEntities) deleteAssociationsButton = QPushButton("Remove all associations") deleteAssociationsButton.clicked.connect(self.deleteAllAssociations) layout = QVBoxLayout() layout.addWidget(deleteClassificationsButton) layout.addWidget(deleteAssociationsButton) layout.addWidget(deleteEntitiesButton) self.databaseBox = QGroupBox("Database") self.databaseBox.setLayout(layout) def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def monthsBetweenDates(self, fromDate, toDate): curDate = QDate(fromDate) months =[] while curDate < toDate: months.append(curDate) curDate = curDate.addMonths(1) return months def makeMonthlyPolarityChart(self, entities, fromDate, toDate): cursor = mysql_conn.cursor() chartData = [] for (entityId, entity) in entities: monthlyPol = self.selectAllPolaritiesForEntity(entityId, fromDate, toDate) trace0=Bar( x = [self.monthYearLabel(month) for (month, _, _) in monthlyPol], y = [(0.0 + rows.count(1L)) / (l+1) * 100 for (_, l, rows) in monthlyPol], name = entity, marker = Marker( color = 'rgb(204,204,204)', opacity = 0.5, ), ) chartData.append(trace0) chartData = Data(chartData) layout = Layout( xaxis=XAxis( #set x-axis' labels direction at 45 degree angle tickangle=-45, ), barmode='group', ) fig = Figure(data = chartData, layout = layout) py.image.save_as({'data': chartData}, "polarities.png") img = Image.open("polarities.png") img.show() def makeMonthlyAppearanceChart(self, entities, fromDate, toDate): cursor = mysql_conn.cursor() chartData = [] for (entityId, entity) in entities: monthlyApp = self.selectCountAssociationsForEntityBetweenDates(entityId, fromDate, toDate) trace0=Bar( x = [self.monthYearLabel(month) for (month, _) in monthlyApp], y = [count for (_, count) in monthlyApp], name = entity, marker = Marker( color = 'rgb(204,204,204)', opacity = 0.5, ), ) chartData.append(trace0) chartData = Data(chartData) layout = Layout( xaxis=XAxis( #set x-axis' labels direction at 45 degree angle tickangle=-45, ), barmode='group', ) fig = Figure(data = chartData, layout = layout) py.image.save_as({'data': chartData}, "appearances.png") img = Image.open("appearances.png") img.show() def getStringDate(self, date): sDate = str(date.year()) sDate += '-'+str(date.month()) sDate += '-'+'01' time = '00:00:00' return sDate + ' ' + time def monthYearLabel(self, date): label = monthIntToString[date.month()] + ' ' label += str(date.year()) return label def createReport(self): reportType = self.reportTypeComboBox.currentText() fromDate = self.fromDateEdit.date() toDate = self.toDateEdit.date() entities = [] if "All entities" in reportType: entities = self.selectAllEntities() else: selected = self.entityList.selectedItems() if len(selected) == 1: entity = selected[0].text() entities = [(self.selectEntityId(entity), entity)] if len(entities) > 0: if "Opinions" in reportType: self.makeMonthlyPolarityChart(entities, fromDate, toDate) else: print entities self.makeMonthlyAppearanceChart(entities, fromDate, toDate) def viewArticle(self): try: articleId = int(self.articleNumberLineEdit.text()) if articleId > 0 and articleId < self.articleCount: self.viewArticleButton.setEnabled(False) self.articleNumberLineEdit.setDisabled(True) articleList = [i+1 for i in xrange(self.articleCount)] articleView = Article(articleId-1, articleList, parentW=self) articleView.exec_() self.viewArticleButton.setEnabled(True) self.articleNumberLineEdit.setDisabled(False) except ValueError: print "Invalid article id" def viewArticleByEntity(self): selected = self.entityList.selectedItems() if len(selected) == 1: articles = self.selectAllArticlesByEntity(selected[0].text()) articleList = [a[0] for a in articles] articleView = Article(0, articleList, shuffle_=True, parentW=self) articleView.exec_() def addEntity(self): newEntity = self.addEntityLineEdit.text().strip() newEntity = re.sub(r' +', ' ', newEntity) cursor = mysql_conn.cursor() if len(newEntity) != 0: selectStmt = """SELECT * FROM entities WHERE entity=%s""" data = (newEntity,) cursor.execute(selectStmt, data) rows = cursor.fetchall() if len(rows) == 0: insertStmt = """INSERT INTO entities (entity) VALUES (%s)""" data = (newEntity,) cursor.execute(insertStmt, data) cursor.execute("""COMMIT""") self.entityUpdate.emit() self.doAssociationsForEntity(newEntity) self.addEntityLineEdit.setText("") def removeEntity(self): selected = self.entityList.selectedItems() cursor = mysql_conn.cursor() for item in selected: self.deleteAssciationsForEntity(item.text()) selectStmt = """SELECT entity_id FROM entities WHERE entity=%s""" data = (item.text(),) cursor.execute(selectStmt, data) entityId = cursor.fetchone() deleteStmt = """DELETE FROM entities WHERE entity_id=%s""" data = (entityId[0],) cursor.execute(deleteStmt, data) cursor.execute("""COMMIT""") self.entityUpdate.emit() def updateEntityList(self): self.entityList.clear() entities = self.selectAllEntities() for entity in entities: self.entityList.addItem(entity[1]) label = "Number of entities: " + str(len(entities)) self.entitiesCountLabel.setText(label) def updateArticleInfo(self): self.articleCount = self.selectCountArticles() entityCount = self.selectCountEntities() associationsCount = self.selectCountAssociations() classifiedCount = self.selectCountClassifiedAssociations() label = "Number of articles: " + str(self.articleCount) self.articleCountLabel.setText(label) label = "Number of entities: " + str(entityCount) self.entitiesCountLabel.setText(label) label = "Number of classified associations: " + str(classifiedCount) self.classifiedCountLabel.setText(label) label = "Number of associations: " + str(associationsCount) self.associationsCountLabel.setText(label) def classifyAllAssociations(self): cursor = mysql_conn.cursor() entities = self.selectAllEntities() for (entityId, entity) in entities: manualPol = self.selectManualPolaritiesForEntity(entityId) trainingData = [self.selectArticle(id_)[4] for (id_, _) in manualPol] trainingTarget = [polarity for (_, polarity) in manualPol] algorithm = self.algorithmComboBox.currentText() textClf = Pipeline([('vect', CountVectorizer()), ('tfidf', TfidfTransformer()), ('clf', classifiers[algorithm]), ]) textClf.fit(trainingData, trainingTarget) # select all articles associated with entity that need to be classified selectStmt = """SELECT article_id FROM assocEntityArticle WHERE polarity_manual IS NULL AND polarity_calculated IS NULL AND entity_id=%s""" data = (entityId,) cursor.execute(selectStmt, data) ids = cursor.fetchall() if len(ids) > 0: ids = [a[0] for a in ids] testData = [self.selectArticle(id_)[4] for id_ in ids] predicted = textClf.predict(testData) print [x for x in predicted].count(1) updateData = zip(predicted, ids) updateData = [(polarity, entityId, id_) for (polarity, id_) in updateData] updateStmt = """UPDATE assocEntityArticle SET polarity_calculated=%s WHERE entity_id=%s AND article_id=%s""" cursor.executemany(updateStmt, updateData) cursor.execute("""COMMIT""") self.articleInfoUpdate.emit() def selectArticle(self, articleId): cursor = mysql_conn.cursor() selectStmt = """SELECT * FROM articles WHERE article_id=%s""" data = (articleId,) cursor.execute(selectStmt, data) row = cursor.fetchone() return row def selectEntityId(self, entity): cursor = mysql_conn.cursor() selectStmt = """SELECT entity_id FROM entities WHERE entity=%s""" data = (entity,) cursor.execute(selectStmt, data) entityId = cursor.fetchone()[0] return entityId def selectAllArticlesByEntity(self, entity): cursor = mysql_conn.cursor() selectStmt = """SELECT * FROM articles WHERE content LIKE %s""" data = ("%" + entity + "%",) cursor.execute(selectStmt, data) rows = cursor.fetchall() return rows def selectAllEntities(self): cursor = mysql_conn.cursor() selectStmt = """SELECT * FROM entities""" cursor.execute(selectStmt) rows = cursor.fetchall() return rows def selectMinAndMaxDate(self): cursor = mysql_conn.cursor() selectStmt = """SELECT MIN(date), MAX(date) FROM articles""" cursor.execute(selectStmt) row = cursor.fetchone() return row def selectCountArticles(self): cursor = mysql_conn.cursor() selectStmt = """SELECT count(*) FROM articles""" cursor.execute(selectStmt) row = cursor.fetchone() return row[0] def selectCountAuthors(self): cursor = mysql_conn.cursor() selectStmt = """SELECT count(*) FROM authors""" cursor.execute(selectStmt) row = cursor.fetchone() return row[0] def selectCountEntities(self): cursor = mysql_conn.cursor() selectStmt = """SELECT count(*) FROM entities""" cursor.execute(selectStmt) row = cursor.fetchone() return row[0] def selectCountAssociations(self): cursor = mysql_conn.cursor() selectStmt = """SELECT count(*) FROM assocEntityArticle""" cursor.execute(selectStmt) row = cursor.fetchone() return row[0] def selectCountAssociationsForEntityBetweenDates(self, entityId, fromDate, toDate): cursor = mysql_conn.cursor() months = self.monthsBetweenDates(fromDate, toDate) selectStmt = """SELECT count(*) FROM assocEntityArticle a, articles b WHERE a.article_id = b.article_id AND b.date BETWEEN %s AND %s AND a.entity_id=%s""" associations = [] if len(months) != 0: for month in months: fromDateString = self.getStringDate(month) toDateString = self.getStringDate(month.addMonths(1)) data = (fromDateString, toDateString, entityId) cursor.execute(selectStmt, data) count = cursor.fetchone()[0] associations.append((month, count)) return associations def selectCountClassifiedAssociations(self): cursor = mysql_conn.cursor() selectStmt = """SELECT count(*) FROM assocEntityArticle WHERE polarity_calculated IS NOT NULL OR polarity_manual IS NOT NULL""" cursor.execute(selectStmt) row = cursor.fetchone() return row[0] def selectManualPolaritiesForEntity(self, entityId): cursor = mysql_conn.cursor() selectStmt = """SELECT article_id, polarity_manual FROM assocEntityArticle WHERE polarity_manual IS NOT NULL AND entity_id=%s""" data = (entityId,) cursor.execute(selectStmt, data) rows = cursor.fetchall() return rows def selectAllPolaritiesForEntity(self, entityId, fromDate, toDate): cursor = mysql_conn.cursor() months = self.monthsBetweenDates(fromDate, toDate) selectStmt = """SELECT a.polarity_manual, a.polarity_calculated FROM assocEntityArticle a, articles b WHERE (a.polarity_manual IS NOT NULL OR a.polarity_calculated IS NOT NULL) AND a.article_id = b.article_id AND b.date BETWEEN %s AND %s AND a.entity_id=%s""" polarities = [] if len(months) != 0: for month in months: fromDateString = self.getStringDate(month) toDateString = self.getStringDate(month.addMonths(1)) data = (fromDateString, toDateString, entityId) cursor.execute(selectStmt, data) rows = cursor.fetchall() rows = [a or b for a, b in rows] polarities.append((month, len(rows), rows)) return polarities def doAssociationsForEntity(self, entity): cursor = mysql_conn.cursor() # select entity_id for entity given as parameter entityId = self.selectEntityId(entity) # select list of article_id for which associations exist # in database for entity given as param selectStmt = """SELECT article_id FROM assocEntityArticle WHERE entity_id=%s""" data = (entityId,) cursor.execute(selectStmt, data) articleIdsInDB = cursor.fetchall() articleIdsInDB = [pair[0] for pair in articleIdsInDB] # select all articles that contain entity in content selectStmt = """SELECT article_id FROM articles WHERE content LIKE %s""" data = ("%" + entity + "%",) cursor.execute(selectStmt, data) rows = cursor.fetchall() rows = [pair[0] for pair in rows] # find articles for which associations don't exist in the database diff = list(set(rows) - set(articleIdsInDB)) if len(diff) != 0: insertStmt = """INSERT INTO assocEntityArticle (article_id, entity_id) VALUES (%s, %s)""" data = [(articleId, entityId) for articleId in diff] cursor.executemany(insertStmt, data) cursor.execute("""COMMIT""") self.articleInfoUpdate.emit() def deleteAssciationsForEntity(self, entity): cursor = mysql_conn.cursor() selectStmt = """SELECT entity_id FROM entities WHERE entity=%s""" data = (entity,) cursor.execute(selectStmt, data) entityId = cursor.fetchone()[0] deleteStmt = """DELETE FROM assocEntityArticle WHERE entity_id=%s""" data = (entityId,) cursor.execute(deleteStmt, data) cursor.execute("""COMMIT""") self.articleInfoUpdate.emit() def doAllAssociations(self): cursor = mysql_conn.cursor() entities = self.selectAllEntities() for entity in entities: self.doAssociationsForEntity(entity) self.articleInfoUpdate.emit() def deleteAllAssociations(self): cursor = mysql_conn.cursor() deleteStmt = """DELETE FROM assocEntityArticle WHERE article_id > 0""" cursor.execute(deleteStmt) cursor.execute("""COMMIT""") self.articleInfoUpdate.emit() def clearAllCalculatedPolarities(self): cursor = mysql_conn.cursor() updateStmt = """UPDATE assocEntityArticle SET polarity_calculated=%s WHERE polarity_calculated IS NOT NULL""" data = (None,) cursor.execute(updateStmt, data) cursor.execute("""COMMIT""") self.articleInfoUpdate.emit() def deleteAllArticles(self): try: cursor = mysql_conn.cursor() deleteStmt = """DELETE FROM articles WHERE article_id > 0""" cursor.execute(deleteStmt) alterTableStmt = """ALTER TABLE articles AUTO_INCREMENT = 1""" cursor.execute(alterTableStmt) cursor.execute("""COMMIT""") self.articleInfoUpdate.emit() except IntegrityError: pass def deleteAllAuthors(self): cursor = mysql_conn.cursor() deleteStmt = """DELETE FROM authors WHERE author_id > 0""" cursor.execute(deleteStmt) alterTableStmt = """ALTER TABLE authors AUTO_INCREMENT = 1""" cursor.execute(alterTableStmt) cursor.execute("""COMMIT""") def deleteAllArticlesAndAuthors(self): self.deleteAllArticles() self.deleteAllAuthors() def deleteAllEntities(self): cursor = mysql_conn.cursor() deleteStmt = """DELETE FROM entities WHERE entity_id > 0""" cursor.execute(deleteStmt) alterTableStmt = """ALTER TABLE entities AUTO_INCREMENT = 1""" cursor.execute(alterTableStmt) cursor.execute("""COMMIT""") self.articleInfoUpdate.emit() self.entityUpdate.emit()
class BuildingServicesClient(QWidget): def __init__(self, parent=None): super(BuildingServicesClient, self).__init__(parent) self.socket = QTcpSocket() self.nextBlockSize = 0 self.request = None roomLabel = QLabel("&Room") self.roomEdit = QLineEdit() roomLabel.setBuddy(self.roomEdit) regex = QRegExp(r"[0-9](?:0[1-9]|[12][0-9]|3[0-4])") self.roomEdit.setValidator(QRegExpValidator(regex, self)) self.roomEdit.setAlignment(Qt.AlignRight | Qt.AlignVCenter) dateLabel = QLabel("&Date") self.dateEdit = QDateEdit() dateLabel.setBuddy(self.dateEdit) self.dateEdit.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.dateEdit.setDate(QDate.currentDate().addDays(1)) self.dateEdit.setDisplayFormat("yyyy-MM-dd") responseLabel = QLabel("Response") self.responseLabel = QLabel() self.responseLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) self.bookButton = QPushButton("&Book") self.bookButton.setEnabled(False) self.unBookButton = QPushButton("&Unbook") self.unBookButton.setEnabled(False) self.bookingsOnDateButton = QPushButton("Bookings &on Date?") self.bookingsForRoomButton = QPushButton("Bookings &for Room?") self.bookingsForRoomButton.setEnabled(False) quitButton = QPushButton("&Quit") if not MAC: self.bookButton.setFocusPolicy(Qt.NoFocus) self.unBookButton.setFocusPolicy(Qt.NoFocus) self.bookingsOnDateButton.setFocusPolicy(Qt.NoFocus) self.bookingsForRoomButton.setFocusPolicy(Qt.NoFocus) buttonLayout = QHBoxLayout() buttonLayout.addWidget(self.bookButton) buttonLayout.addWidget(self.unBookButton) buttonLayout.addWidget(self.bookingsOnDateButton) buttonLayout.addWidget(self.bookingsForRoomButton) buttonLayout.addStretch() buttonLayout.addWidget(quitButton) layout = QGridLayout() layout.addWidget(roomLabel, 0, 0) layout.addWidget(self.roomEdit, 0, 1) layout.addWidget(dateLabel, 0, 2) layout.addWidget(self.dateEdit, 0, 3) layout.addWidget(responseLabel, 1, 0) layout.addWidget(self.responseLabel, 1, 1, 1, 3) layout.addLayout(buttonLayout, 2, 0, 1, 5) self.setLayout(layout) self.socket.connected.connect(self.sendRequest) self.socket.readyRead.connect(self.readResponse) self.socket.disconnected.connect(self.serverHasStopped) #self.connect(self.socket, # SIGNAL("error(QAbstractSocket::SocketError)"), # self.serverHasError) self.socket.error.connect(self.serverHasError) self.roomEdit.textEdited.connect(self.updateUi) self.dateEdit.dateChanged.connect(self.updateUi) self.bookButton.clicked.connect(self.book) self.unBookButton.clicked.connect(self.unBook) self.bookingsOnDateButton.clicked.connect(self.bookingsOnDate) self.bookingsForRoomButton.clicked.connect(self.bookingsForRoom) quitButton.clicked.connect(self.close) self.setWindowTitle("Building Services") def updateUi(self): enabled = False if (self.roomEdit.text() and self.dateEdit.date() > QDate.currentDate()): enabled = True if self.request is not None: enabled = False self.bookButton.setEnabled(enabled) self.unBookButton.setEnabled(enabled) self.bookingsForRoomButton.setEnabled(enabled) def closeEvent(self, event): self.socket.close() event.accept() def book(self): self.issueRequest("BOOK", self.roomEdit.text(), self.dateEdit.date()) def unBook(self): self.issueRequest("UNBOOK", self.roomEdit.text(), self.dateEdit.date()) def bookingsOnDate(self): self.issueRequest("BOOKINGSONDATE", self.roomEdit.text(), self.dateEdit.date()) def bookingsForRoom(self): self.issueRequest("BOOKINGSFORROOM", self.roomEdit.text(), self.dateEdit.date()) def issueRequest(self, action, room, date): self.request = QByteArray() stream = QDataStream(self.request, QIODevice.WriteOnly) stream.setVersion(QDataStream.Qt_5_7) stream.writeUInt16(0) stream.writeQString(action) stream.writeQString(room) stream << date stream.device().seek(0) stream.writeUInt16(self.request.size() - SIZEOF_UINT16) self.updateUi() if self.socket.isOpen(): self.socket.close() self.responseLabel.setText("Connecting to server...") self.socket.connectToHost("localhost", PORT) def sendRequest(self): self.responseLabel.setText("Sending request...") self.nextBlockSize = 0 self.socket.write(self.request) self.request = None def readResponse(self): stream = QDataStream(self.socket) stream.setVersion(QDataStream.Qt_5_7) while True: if self.nextBlockSize == 0: if self.socket.bytesAvailable() < SIZEOF_UINT16: break self.nextBlockSize = stream.readUInt16() if self.socket.bytesAvailable() < self.nextBlockSize: break action = "" room = "" date = QDate() action = stream.readQString() room = stream.readQString() if action == "BOOKINGSFORROOM": dates = [] for x in range(stream.readInt32()): stream >> date dates.append(str(date.toString(Qt.ISODate))) dates = ", ".join(dates) if action not in ("BOOKINGSFORROOM", "ERROR"): stream >> date if action == "ERROR": msg = "Error: {0}".format(room) elif action == "BOOK": msg = "Booked room {0} for {1}".format( room, date.toString(Qt.ISODate)) elif action == "UNBOOK": msg = "Unbooked room {0} for {1}".format( room, date.toString(Qt.ISODate)) elif action == "BOOKINGSONDATE": msg = "Rooms booked on {0}: {1}".format( date.toString(Qt.ISODate), room) elif action == "BOOKINGSFORROOM": msg = "Room {0} is booked on: {1}".format(room, dates) self.responseLabel.setText(msg) self.updateUi() self.nextBlockSize = 0 def serverHasStopped(self): self.responseLabel.setText("Error: Connection closed by server") self.socket.close() def serverHasError(self, error): self.responseLabel.setText("Error: {0}".format( self.socket.errorString())) self.socket.close()