class BufferSelectToolbar(object): def __init__(self, selectTool): super(BufferSelectToolbar, self).__init__() # references self.selectTool = selectTool self.result = None self.debug = self.selectTool.debug self.id = id self.config = self.selectTool.config self.info = Info(self) try: self.gtomain = self.selectTool.gtomain self.helper = self.gtomain.helper self.metadata = self.gtomain.metadata self.iface = self.gtomain.iface self.canvas = self.iface.mapCanvas() # tool data self.toolbar_dock = self.config.get("toolbar_dock", 4) self.toolbar_height = self.gtomain.toolbar_height # widget self.toolbar = None # load toolbar objName = "gtoTB_" + __name__ + str(id) self.toolbar = self.gtomain.helper.findToolbar(self.iface, objName) if self.toolbar is None: if self.debug: self.info.log("load", objName) self.toolbar = QToolBar() self.toolbar.setObjectName(objName) self.toolbar.setWindowTitle(u'GTO Buffer Selection') self.toolbar.setAllowedAreas(Qt.BottomToolBarArea | Qt.TopToolBarArea) self.iface.mainWindow().addToolBarBreak(self.toolbar_dock) self.iface.addToolBar(self.toolbar, self.toolbar_dock) # set the iconsize=> changed when self.iface.addToolBar :S if self.toolbar_height is not None: self.toolbar.setMaximumHeight(self.gtomain.toolbar_height) self.toolbar.setMinimumHeight(self.gtomain.toolbar_height) else: self.toolbar.clear() self.wid = Widget(self) self.toolbar.addWidget(self.wid) self.wid.setIconSizes(self.iface.iconSize(False)) self.wid.geometry_changed.connect(self.getGeometry) self.toolbar.setHidden(False) except Exception as e: self.info.err(e) # from mActionbufferselectxy def setHidden(self, a0): self.toolbar.setHidden(a0) def setGeometry(self, geo, isValid, isCircle=False, isRectangle=False): self.toolbar.setHidden(False) if self.debug: self.info.log("setGeometry", geo.isEmpty(), isValid, isCircle, isRectangle) self.wid.setOriginalGeometry(geo, isValid, isCircle, isRectangle) def getGeometry(self, geo): self.selectTool.setGeometryToMapTool(geo)
class Tab(QWidget): """Tab in the QTableWidget where user executes query and sees the result.""" # ---------------------------------------------------------------------- def __init__(self): """Initialize Tab with layout and behavior.""" super(Tab, self).__init__() # regex pattern for SQL query block comments self.block_comment_re = re.compile( r'(^)?[^\S\n]*/(?:\*(.*?)\*/[^\S\n]*|/[^\n]*)($)?', re.DOTALL | re.MULTILINE) main_layout = QVBoxLayout(self) # define gdb props self.gdb = None self.gdb_items = None self.gdb_columns_names = None self.gdb_schemas = None # connected geodatabase path toolbar self.connected_gdb_path_label = QLabel('') self.connected_gdb_path_label.setTextInteractionFlags( Qt.TextSelectableByMouse) self.connected_gdb_path_label.setToolTip( 'Connected geodatabase that queries will be run against') self.connected_gdb_path_label.setText(not_connected_to_gdb_message) self.browse_to_gdb = QPushButton('Browse') self.browse_to_gdb.setShortcut(QKeySequence('Ctrl+B')) self.browse_to_gdb.clicked.connect( lambda evt, arg=True: self.connect_to_geodatabase( evt, triggered_with_browse=True)) self.gdb_sql_dialect_combobox = QComboBox() for dialect in sql_dialects_names: self.gdb_sql_dialect_combobox.addItem(dialect) self.gdb_browse_toolbar = QToolBar() self.gdb_browse_toolbar.setMaximumHeight(50) self.gdb_browse_toolbar.addWidget(self.browse_to_gdb) self.gdb_browse_toolbar.addWidget(self.connected_gdb_path_label) self.gdb_browse_toolbar.addSeparator() self.gdb_browse_toolbar.addWidget(self.gdb_sql_dialect_combobox) # table with results self.table = ResultTable() # execute SQL query self.execute = QAction('Execute', self) self.execute.setShortcuts( [QKeySequence('F5'), QKeySequence('Ctrl+Return')]) self.execute.triggered.connect(self.run_query) self.addAction(self.execute) # enter a SQL query self.query = TextEditor() self.query.setPlainText('') font = self.query.font() font.setFamily('Consolas') font.setStyleHint(QFont.Monospace) # TODO: add line numbers to the text editor font.setPointSize(14) self.query.setFont(font) self.query.setTabStopWidth(20) self.highlighter = Highlighter(self.query.document()) # TODO select block of text - Ctrl+/ and they become comments self.completer = Completer() self.query.set_completer(self.completer.completer) # errors panel to show if query fails to execute properly self.errors_panel = QPlainTextEdit() font = self.query.font() font.setPointSize(12) self.errors_panel.setStyleSheet('color:red') self.errors_panel.setFont(font) self.errors_panel.hide() # splitter between the toolbar, query window, and the result set table splitter = QSplitter(Qt.Vertical) splitter.addWidget(self.gdb_browse_toolbar) splitter.addWidget(self.query) splitter.addWidget(self.table) splitter.addWidget(self.errors_panel) # add the settings after the widget have been added splitter.setCollapsible(0, True) splitter.setCollapsible(1, False) splitter.setCollapsible(2, False) splitter.setCollapsible(3, False) splitter.setStretchFactor(0, 3) splitter.setStretchFactor(1, 7) splitter.setSizes((100, 200, 300)) self.table.hide() # TOC self.toc = QTreeWidget() self.toc.setHeaderHidden(True) # second splitter between the TOC to the left and the query/table to the # right toc_splitter = QSplitter(Qt.Horizontal) toc_splitter.addWidget(self.toc) toc_splitter.addWidget(splitter) toc_splitter.setCollapsible(0, True) toc_splitter.setSizes((200, 800)) # set the TOC vs data panel main_layout.addWidget(toc_splitter) margins = QMargins() margins.setBottom(10) margins.setLeft(10) margins.setRight(10) margins.setTop(10) main_layout.setContentsMargins(margins) self.setLayout(main_layout) QApplication.setStyle(QStyleFactory.create('Cleanlooks')) self.show() return # ---------------------------------------------------------------------- def connect_to_geodatabase(self, evt, triggered_with_browse=True): """Connect to geodatabase by letting user browse to a gdb folder.""" if triggered_with_browse: gdb_connect_dialog = QFileDialog(self) gdb_connect_dialog.setFileMode(QFileDialog.Directory) gdb_path = gdb_connect_dialog.getExistingDirectory() # TODO: add a filter to show only .gdb folders? # https://stackoverflow.com/questions/4893122/filtering-in-qfiledialog if gdb_path and gdb_path.endswith('.gdb'): self.gdb = Geodatabase(gdb_path) if self.gdb.is_valid(): self.connected_gdb_path_label.setText(self.gdb.path) self._set_gdb_items_highlight() self._set_gdb_items_complete() self._fill_toc() else: msg = QMessageBox() msg.setText('This is not a valid file geodatabase') msg.setWindowTitle('Validation error') msg.setStandardButtons(QMessageBox.Ok) msg.exec_() else: if self.gdb.is_valid(): self._set_gdb_items_highlight() self._set_gdb_items_complete() return # ---------------------------------------------------------------------- def wheelEvent(self, event): # noqa: N802 """Override built-in method to handle mouse wheel scrolling. Necessary to do when the tab is focused. """ modifiers = QApplication.keyboardModifiers() if modifiers == Qt.ControlModifier: if event.angleDelta().y() > 0: # scroll forward self.query.zoomIn(1) else: self.query.zoomOut(1) return # ---------------------------------------------------------------------- def run_query(self): """Run SQL query and draw the record set and call table drawing.""" if not self.gdb: self.print_sql_execute_errors(not_connected_to_gdb_message) return try: if not self.gdb.is_valid(): return # use the text of what user selected, if none -> need to run the # whole query part_sql_query = self.query.textCursor().selection().toPlainText() if part_sql_query: sql_query = part_sql_query else: sql_query = self.query.toPlainText() if sql_query: # removing block comments and single line comments sql_query = self.block_comment_re.sub( self._strip_block_comments, sql_query) sql_query = self._strip_single_comments(sql_query) else: return # TODO: add threading to allow user to cancel a long running query QApplication.setOverrideCursor(Qt.WaitCursor) start_time = time.time() self.gdb.open_connection() res, errors = self.gdb.execute_sql( sql_query, self.gdb_sql_dialect_combobox.currentText()) end_time = time.time() if errors: self.print_sql_execute_errors(errors) if res: self.table.show() self.errors_panel.hide() self.draw_result_table(res) msg = 'Executed in {exec_time:.1f} secs | {rows} rows'.format( exec_time=end_time - start_time, rows=self.table.table_data.number_layer_rows) self.update_app_status_bar(msg) except Exception as err: print(err) finally: QApplication.restoreOverrideCursor() return # ---------------------------------------------------------------------- def result_should_include_geometry(self): """Get the setting defining whether to include the geometry column.""" try: return self.parentWidget().parentWidget().parentWidget( ).do_include_geometry.isChecked() except Exception: return True # ---------------------------------------------------------------------- def update_app_status_bar(self, message): """Update app status bar with the execution result details.""" try: self.parentWidget().parentWidget().parentWidget().statusBar( ).showMessage(message) except Exception: pass return # ---------------------------------------------------------------------- def draw_result_table(self, res): """Draw table with the record set received from the geodatabase.""" geom_col_name = res.GetGeometryColumn( ) # shape col was in the sql query self.geometry_isin_query = bool(geom_col_name) self.table.draw_result(res, show_shapes=bool( self.result_should_include_geometry())) self.table.view.resizeColumnsToContents() return # ---------------------------------------------------------------------- def print_sql_execute_errors(self, err): """Print to a special panel errors that occurred during execution.""" self.table.hide() self.errors_panel.show() self.errors_panel.setPlainText(err) return # ---------------------------------------------------------------------- def _set_gdb_items_highlight(self): """Set completer and highlight properties for geodatabase items.""" self.gdb_items = self.gdb.get_items() self.highlighter.set_highlight_rules_gdb_items(self.gdb_items, 'Table') self.gdb_schemas = self.gdb.get_schemas() self.gdb_columns_names = sorted(list( set( itertools.chain.from_iterable( [i.keys() for i in self.gdb_schemas.values()]))), key=lambda x: x.lower()) # ---------------------------------------------------------------------- def _set_gdb_items_complete(self): """Update completer rules to include geodatabase items.""" self.completer.update_completer_string_list(self.gdb_items + self.gdb_columns_names) self.highlighter.set_highlight_rules_gdb_items(self.gdb_columns_names, 'Column') return # ---------------------------------------------------------------------- def _fill_toc(self): """Fill TOC with geodatabase datasets and columns.""" self.toc.clear() if not self.gdb_items: return for tbl_name in sorted(self.gdb_items, key=lambda i: i.lower()): if tbl_name.islower() or tbl_name.isupper(): item = QTreeWidgetItem([tbl_name.title()]) else: item = QTreeWidgetItem([tbl_name]) font = QFont() font.setBold(True) item.setFont(0, font) for col_name, col_type in sorted( self.gdb_schemas[tbl_name].items()): if col_name.islower() or col_name.isupper(): col_name = col_name.title() item_child = QTreeWidgetItem( ['{0} ({1})'.format(col_name, col_type)]) item.addChild(item_child) self.toc.addTopLevelItem(item) return # ---------------------------------------------------------------------- def _do_toc_hide_show(self): """Hide TOC with tables and columns.""" if self.toc.isVisible(): self.toc.setVisible(False) else: self.toc.setVisible(True) return # ---------------------------------------------------------------------- def _strip_block_comments(self, sql_query): """Strip the block comments in SQL query.""" start, mid, end = sql_query.group(1, 2, 3) if mid is None: # this is a single-line comment return '' elif start is not None or end is not None: # this is a multi-line comment at start/end of a line return '' elif '\n' in mid: # this is a multi-line comment with line break return '\n' else: # this is a multi-line comment without line break return ' ' # ---------------------------------------------------------------------- def _strip_single_comments(self, sql_query): """Strip the single line comments in SQL query.""" clean_query = [] for line in sql_query.rstrip().split('\n'): clean_line = line.split('--')[0] if clean_line: clean_query.append(clean_line) return ' '.join([line for line in clean_query])
class MainWindow(QMainWindow): # initialize the main window def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.init_ui() self.show() self.rgb = [128, 128, 128] self.xy = [0, 0] self.hw = [0, 0] self.filter = 1 self.handler.handle_open_for_json() QApplication.clipboard().dataChanged.connect(self.clipboardChanged) self.clipboardChanged() self.resize(1280, 768) # self.handler.handle_stow() def init_ui(self): self.setWindowTitle("Cute Image Editor") self.central_widget = QWidget() self.gridLayout = QGridLayout() self.central_widget.setLayout(self.gridLayout) self.setCentralWidget(self.central_widget) self.resize(1280, 768) # Add the click handler self.handler = ClickHandler(self) # Main editing area self.mdiArea = IWindow(self) # Left window~ self.lwindow = LWindow(self) # Right window self.rwindow = RWindow(self) # Bottom window self.bwindow = BWindow(self) # Add components to the main grid layout self.init_grid() self.init_tool_bar() self.init_menu_bar() def init_grid(self): self.gridLayout.setSpacing(2) self.gridLayout.addWidget(self.lwindow, 1, 1) self.gridLayout.addWidget(self.mdiArea, 1, 2) self.gridLayout.addWidget(self.rwindow, 1, 3) self.gridLayout.addWidget(self.bwindow, 2, 1, 1, 3) self.gridLayout.setColumnMinimumWidth(1, 220) self.gridLayout.setColumnMinimumWidth(2, 900) self.gridLayout.setColumnMinimumWidth(3, 220) self.gridLayout.setRowMinimumHeight(1, 500) self.gridLayout.setRowMinimumHeight(2, 140) def init_tool_bar(self): self.toolbar = QToolBar("Shortcuts") self.addToolBar(self.toolbar) # action_list = [[self.open_action, self.save_action, self.info_action, self.quit_action, self.search_help_action], # [self.original_color_action, self.reverse_action, self.to_grayscale_action, self], # [self.saturate_red_action, self.saturate_blue_action, self.saturate_green_action], # [self.threshold_action, self.blur_action, self.sharpen_action], # [self.ccl_action, self.hsl_action, self.outline_action], # [self.floyd_action, self.rgb_action, self.crop_action]] # for sublist in action_list: # for action in sublist: # self.toolbar.addAction(QAction(action)) # self.toolbar.addSeparator() self.toolbar.setMaximumHeight(30) self.toolbar.setMinimumHeight(30) def init_menu_bar(self): # Create menus in the menu bar as following # File Edit View Image Processing Profile Window Help self.file_menu = QMenu("&File") self.menuBar().addMenu(self.file_menu) self.edit_menu = QMenu("&Edit") self.menuBar().addMenu(self.edit_menu) self.view_menu = QMenu("&View") self.menuBar().addMenu(self.view_menu) self.image_menu = QMenu("&Image") self.menuBar().addMenu(self.image_menu) self.processing_menu = QMenu("Processing") self.menuBar().addMenu(self.processing_menu) self.share_menu = QMenu("Share") self.menuBar().addMenu(self.share_menu) self.window_menu = QMenu("&Window") self.menuBar().addMenu(self.window_menu) self.help_menu = QMenu("&Help") self.menuBar().addMenu(self.help_menu) # Create actions for each menu # Actions for File menu self.open_action = MyImageAction(self, "&Open...", self.file_menu, self.handler.handle_open, "Ctrl+O", "open.png") self.save_action = MyImageAction(self, "&Save...", self.file_menu, self.handler.handle_save, "Ctrl+S", "save_as.png") self.info_action = MyImageAction(self, "&Get Info...", self.file_menu, self.handler.handle_info, "Ctrl+I", "info.png") self.camera_action = MyImageAction(self, "&Camera", self.edit_menu, self.handler.handle_camera, "", "camera.png") self.url_action = MyImageAction(self, "&Open URL", self.edit_menu, self.handler.handle_url, "", "url.png") self.clipboard_action = MyImageAction(self, "&Copy To Clipboard", self.edit_menu, self.handler.handle_clipboard, "", "clipboard.png") self.show_folder_action = MyImageAction(self, "&Show In Finder", self.file_menu, self.handler.handle_finder, "Ctrl+F", "finder.png") self.open_with_app_action = MyImageAction( self, "&Open With App", self.file_menu, self.handler.handle_open_with_app, "", "app.png") self.instagram_action = MyImageAction(self, "&Share In Instagram", self.share_menu, self.handler.handle_instagram, "", "instagram.png") self.twitter_action = MyImageAction(self, "&Share In Twitter", self.share_menu, self.handler.handle_twitter, "", "twitter.png") self.snapchat_action = MyImageAction(self, "&Share In Snapchat", self.share_menu, self.handler.handle_snapchat, "", "snapchat.png") # Actions for Processing menu self.original_color_action = MyImageAction( self, "&Original color", self.image_menu, self.handler.handle_original_color, "", "origin.png") self.reverse_action = MyImageAction(self, "&Reverse", self.image_menu, self.handler.handle_reverse, "", "reverse.png") self.to_grayscale_action = MyImageAction( self, "&Black and white", self.image_menu, self.handler.handle_to_grayscale, "", "to_grayscale.png") self.image_menu.addSeparator() self.saturate_red_action = MyImageAction( self, "&Saturate in red", self.image_menu, self.handler.handle_saturate_red, "", "saturate_red.png") self.saturate_green_action = MyImageAction( self, "&Saturate in green", self.image_menu, self.handler.handle_saturate_green, "", "saturate_green.png") self.saturate_blue_action = MyImageAction( self, "&Saturate in blue", self.image_menu, self.handler.handle_saturate_blue, "", "saturate_blue.png") self.threshold_action = MyImageAction(self, "&Threshold", self.processing_menu, self.handler.handle_threshold, "", "threshold.png") self.blur_action = MyImageAction(self, "&Blur", self.processing_menu, self.handler.handle_blur, "", "blur.png") self.gaussian_blur_action = MyImageAction( self, "&Gaussian Blur", self.processing_menu, self.handler.handle_gaussian_blur, "", "gaussian.png") self.box_blur_action = MyImageAction(self, "&Box Blur", self.processing_menu, self.handler.handle_box_blur, "", "box.png") self.sharpen_action = MyImageAction(self, "&Sharpen", self.processing_menu, self.handler.handle_sharpen, "", "sharpen.png") self.processing_menu.addSeparator() self.filter_action = MyImageAction(self, "&Filter", self.processing_menu, self.handler.handle_filter, "", "filter.png") self.ccl_action = MyImageAction(self, "&CCL", self.processing_menu, self.handler.handle_ccl, "", "CCL.png") # self.hsl_action = MyImageAction(self, "&HSL", self.processing_menu, self.handler.handle_hsl, "", "hsl.png") self.outline_action = MyImageAction(self, "&Outline detection", self.processing_menu, self.handler.handle_outline, "", "outline.png") self.smooth_action = MyImageAction(self, "&Smooth", self.processing_menu, self.handler.handle_smooth, "", "smooth.png") self.smooth_more_action = MyImageAction( self, "&Smooth More", self.processing_menu, self.handler.handle_smooth_more, "", "smooth.png") self.detail_action = MyImageAction(self, "&Detail", self.processing_menu, self.handler.handle_detail, "", "detail.png") self.emboss_action = MyImageAction(self, "&Emboss", self.processing_menu, self.handler.handle_emboss, "", "emboss.png") self.edge_action = MyImageAction(self, "&Edge", self.processing_menu, self.handler.handle_edge, "", "edge.png") self.edge_more_action = MyImageAction(self, "&Edge More", self.processing_menu, self.handler.handle_edge_more, "", "edge.png") self.find_edges_action = MyImageAction(self, "&Find Edges", self.processing_menu, self.handler.handle_find_edges, "", "find_edges.png") self.processing_menu.addSeparator() self.min_filter_action = MyImageAction(self, "&Min Filter", self.processing_menu, self.handler.handle_min_filter, "", "filter-512.png") self.max_filter_action = MyImageAction(self, "&Max Filter", self.processing_menu, self.handler.handle_max_filter, "", "filter-512.png") self.median_filter_action = MyImageAction( self, "&Median Filter", self.processing_menu, self.handler.handle_median_filter, "", "filter-512.png") self.rank_filter_action = MyImageAction( self, "&Rank Filter", self.processing_menu, self.handler.handle_rank_filter, "", "filter-512.png") self.processing_menu.addSeparator() self.floyd_action = MyImageAction(self, "&Dithering", self.processing_menu, self.handler.handle_dithering, "", "floyd.png") self.rgb_action = MyImageAction(self, "&RGB", self.processing_menu, self.handler.handle_rgb, "", "rgb.png") self.crop_action = MyImageAction(self, "&Crop", self.processing_menu, self.handler.handle_crop, "", "crop.png") self.timer_action = MyImageAction(self, "&Timer", self.processing_menu, self.handler.handle_timer, "", "timer.png") self.kernel_action = MyImageAction(self, "&Kernel", self.processing_menu, self.handler.handle_kernel, "", "kernel.png") self.view_menu.addSeparator() self.toggle_l_action = MyImageAction(self, "&Toggle Left", self.view_menu, self.handler.handle_toggle_l, "Ctrl+1", "l_window.png") self.toggle_r_action = MyImageAction(self, "&Toggle Right", self.view_menu, self.handler.handle_toggle_r, "Ctrl+2", "r_window.png") self.toggle_b_action = MyImageAction(self, "&Toggle Bottom", self.view_menu, self.handler.handle_toggle_b, "Ctrl+0", "b_window.png") self.view_menu.addSeparator() self.close_all_action = MyImageAction(self, "&Close All", self.window_menu, self.handler.handle_close_all, "", "close.png") self.quit_action = MyImageAction(self, "&Quit", self.file_menu, self.close, "Ctrl+Q", "quit.png") self.search_help_action = QAction("&Search help...", self) self.actions = [ [self.open_action, self.save_action, self.info_action], [self.camera_action, self.clipboard_action], [ self.url_action, self.show_folder_action, self.open_with_app_action ], [self.instagram_action, self.twitter_action, self.snapchat_action], [ QAction(), QAction(), QAction(), QAction(), QAction(), QAction(), QAction(), QAction(), QAction(), QAction(), QAction(), QAction(), QAction() ], [self.toggle_l_action, self.toggle_r_action, self.toggle_b_action], [self.close_all_action, self.quit_action] ] for sub_list in self.actions: for action in sub_list: self.toolbar.addAction(action) if sub_list != self.actions[-1] and sub_list != self.actions[ -3] and sub_list != self.actions[-4]: self.toolbar.addSeparator() self.help_menu.addAction(self.search_help_action) def get_rgb(self): return self.rgb def get_xy(self): return self.xy def get_hw(self): return self.hw def clipboardChanged(self): self.clip_board_text = QApplication.clipboard().text() self.clip_board_image = QApplication.clipboard().image() def set_rgb(self, r=128, g=128, b=128): self.rgb = [r, g, b] def closeEvent(self, event): self.handler.handle_close_event()