示例#1
0
class MultiLayerSelect:
    """QGIS Plugin Implementation."""
    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value("locale/userLocale")[0:2]
        locale_path = os.path.join(self.plugin_dir, "i18n",
                                   "MultiLayerSelect_{}.qm".format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

        # Init settings
        self.settings = QSettings()
        self.settings.beginGroup("plugins/multilayerselect")

    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # pylint: disable=invalid-name

        return QCoreApplication.translate("MultiLayerSelect", message)

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""
        # pylint: disable=invalid-name

        # Create settings dialog
        self.settings_dialog = SettingsDialog(self.settings,
                                              self.iface.mainWindow())
        self.expression_dialog = None

        try:
            QgsProject.instance().selectionColorChanged.connect(
                self.on_color_changed)
            QgsProject.instance().selectionColorChanged.connect(
                self.settings_dialog.on_project_color_changed)
        except AttributeError:  # QGIS < 3.10
            self.settings_dialog.colorChanged.connect(self.on_color_changed)
            QgsProject.instance().readProject.connect(
                self.settings_dialog.on_project_color_changed)

        self.settings_dialog.settingsChanged.connect(self.on_settings_changed)

        self.toolbar = QToolBar("Multilayer Select", self.iface.mainWindow())
        self.toolbar.setObjectName("MultiSelectToolbar")

        self.about_action = QAction(
            QIcon(":/plugins/multilayerselect/icons/about.svg"),
            self.tr("About"),
            parent=self.iface.mainWindow(),
        )
        self.about_action.triggered.connect(self.show_about)

        self.settings_action = QAction(
            QIcon(":/images/themes/default/console/iconSettingsConsole.svg"),
            self.tr("Settings"),
            parent=self.iface.mainWindow(),
        )
        self.settings_action.setObjectName("actionMultiLayerSelectSettings")
        self.settings_action.setToolTip(
            self.tr("<b>Multilayer Select Settings</b>"))

        self.settings_action.triggered.connect(self.show_settings)

        self.plugin_menu = self.iface.pluginMenu().addMenu(
            QIcon(":/plugins/multilayerselect/icons/icon.svg"),
            "Multilayer Select")
        self.plugin_menu.addAction(self.about_action)
        self.plugin_menu.addAction(self.settings_action)

        self.selection_tool_button = QToolButton(self.toolbar)
        self.selection_tool_button.setPopupMode(QToolButton.MenuButtonPopup)
        self.selection_tool_button.setObjectName("selectionToolButton")

        self.advanced_selection_tool_button = QToolButton(self.toolbar)
        self.advanced_selection_tool_button.setPopupMode(
            QToolButton.MenuButtonPopup)
        self.advanced_selection_tool_button.setObjectName(
            "advancedSelectionToolButton")

        self.select_rect_tool = MultiSelectionAreaTool(self.iface.mapCanvas())
        self.select_polygon_tool = MultiSelectionPolygonTool(
            self.iface.mapCanvas())
        self.select_freehand_tool = MultiSelectionFreehandTool(
            self.iface.mapCanvas())
        self.select_radius_tool = MultiSelectionRadiusTool(
            self.iface.mapCanvas())

        self.actions_settings = [
            SelectAction(
                text=self.tr("Select Features"),
                tooltip=self.tr(
                    "<b>Select Features by area or single click</b>"),
                icon=":/plugins/multilayerselect/icons/selectRectangle.svg",
                objectname="actionMultiSelectByRectangle",
                tool=self.select_rect_tool,
            ),
            SelectAction(
                text=self.tr("Select Features by Polygon"),
                icon=":/plugins/multilayerselect/icons/selectPolygon.svg",
                objectname="actionMultiSelectByPolygon",
                tool=self.select_polygon_tool,
            ),
            SelectAction(
                text=self.tr("Select Features by Freehand"),
                icon=":/plugins/multilayerselect/icons/selectFreehand.svg",
                objectname="actionMultiSelectByFreehand",
                tool=self.select_freehand_tool,
            ),
            SelectAction(
                text=self.tr("Select Features by Radius"),
                icon=":/plugins/multilayerselect/icons/selectRadius.svg",
                objectname="actionMultiSelectByRadius",
                tool=self.select_radius_tool,
            ),
        ]

        def on_select_tool(tool, action):
            self.selection_tool_button.setDefaultAction(action)
            if self.embedded_selection_tool_button:
                self.embedded_selection_tool_button.setDefaultAction(action)
            self.iface.mapCanvas().setMapTool(tool)

        self.select_actions = []

        for select_action in self.actions_settings:
            action = QAction(select_action.text)
            action.setToolTip(select_action.tooltip)
            action.setObjectName(select_action.objectname)
            action.setCheckable(True)
            select_action.tool.setAction(action)

            action.triggered.connect(
                partial(on_select_tool, select_action.tool, action))
            self.selection_tool_button.addAction(action)
            if not self.selection_tool_button.defaultAction():
                self.selection_tool_button.setDefaultAction(action)
            self.select_actions.append(action)

        self.toolbar.addWidget(self.selection_tool_button)

        self.select_all_action = QAction(
            self.tr("Select all features from all layers"), )
        self.select_all_action.setToolTip("<b>{}</b>".format(
            self.select_all_action.text()))
        self.select_all_action.setObjectName("actionMultiSelectAll")
        self.select_all_action.triggered.connect(self.select_all)
        self.advanced_selection_tool_button.addAction(self.select_all_action)
        self.advanced_selection_tool_button.setDefaultAction(
            self.select_all_action)

        self.invert_all_action = QAction(
            self.tr("Invert selection for all layers"), )
        self.invert_all_action.setToolTip("<b>{}</b>".format(
            self.invert_all_action.text()))
        self.invert_all_action.setObjectName("actionMultiSelectInvert")
        self.invert_all_action.triggered.connect(self.invert_all)
        self.advanced_selection_tool_button.addAction(self.invert_all_action)

        self.select_by_expr_action = QAction(
            QIcon(":/images/themes/default/mIconExpressionSelect.svg"),
            self.tr("Select Features by Expression..."),
        )
        self.select_by_expr_action.setToolTip("<b>{}</b>".format(
            self.select_by_expr_action.text()))
        self.select_by_expr_action.setObjectName("actionMultiSelectExpr")
        self.select_by_expr_action.triggered.connect(self.select_by_expression)
        self.advanced_selection_tool_button.addAction(
            self.select_by_expr_action)

        self.toolbar.addWidget(self.advanced_selection_tool_button)

        self.deselect_all_action = QAction(
            self.tr("Deselect features from all layers"))
        self.deselect_all_action.setToolTip("<b>{}</b>".format(
            self.deselect_all_action.text()))
        self.deselect_all_action.setObjectName("actionDeselectAll")
        self.deselect_all_action.triggered.connect(self.deselect_all)
        self.toolbar.addAction(self.deselect_all_action)

        self.toolbar.addAction(self.settings_action)

        self.iface.mainWindow().addToolBar(self.toolbar)

        # Embedded actions
        self.embedded_selection_tool_button_action = None
        self.embedded_selection_tool_button = None
        self.embedded_advanced_tool_button_action = None
        self.embedded_advanced_tool_button = None

        self.on_color_changed()
        self.on_settings_changed()

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""

        # Delete Settings dialog
        self.settings_dialog.deleteLater()

        # Remove menu from plugins menu
        self.iface.pluginMenu().removeAction(self.plugin_menu.menuAction())

        self.select_freehand_tool.deleteLater()
        self.select_polygon_tool.deleteLater()
        self.select_radius_tool.deleteLater()
        self.select_rect_tool.deleteLater()

        self.iface.mainWindow().removeToolBar(self.toolbar)
        self.toolbar.deleteLater()

        self.replace_default_action(False)

        try:
            QgsProject.instance().selectionColorChanged.disconnect(
                self.on_color_changed)
            QgsProject.instance().selectionColorChanged.disconnect(
                self.settings_dialog.on_project_color_changed)

        except AttributeError:  # QGIS < 3.10
            pass

    def show_about(self):
        """ Show the about dialog """

        # Used to display plugin icon in the about message box
        bogus = QWidget(self.iface.mainWindow())
        bogus.setWindowIcon(QIcon(":/plugins/multilayerselect/icons/icon.svg"))

        cfg = configparser.ConfigParser()
        cfg.read(os.path.join(os.path.dirname(__file__), "metadata.txt"))
        version = cfg.get("general", "version")
        homepage = cfg.get("general", "homepage")
        tracker = cfg.get("general", "tracker")
        repository = cfg.get("general", "repository")

        QMessageBox.about(
            bogus,
            self.tr("About Multilayer Select"),
            "<b>Version</b> {3}<br><br>"
            "<b>{4}</b> : <a href={0}>GitHub</a><br>"
            "<b>{5}</b> : <a href={1}>GitHub</a><br>"
            "<b>{6}</b> : <a href={2}>GitHub Pages</a>".format(
                repository,
                tracker,
                homepage,
                version,
                self.tr("Source code"),
                self.tr("Report issues"),
                self.tr("Documentation"),
            ),
        )

        bogus.deleteLater()

    def show_settings(self):
        """ Show the settings dialog """

        geometry = self.settings_dialog.geometry()

        # The first time the dialog is shown (y=0), explicitely set its geometry
        # which allow to restore the geometry on subsequent calls
        if geometry.y() == 0:
            self.settings_dialog.show()
            self.settings_dialog.raise_()
            self.settings_dialog.setGeometry(self.settings_dialog.geometry())
            return

        self.settings_dialog.show()
        self.settings_dialog.raise_()

    def on_color_changed(self):
        """ Called when the selection color has changed. Replace every icon """
        color = self.iface.mapCanvas().selectionColor()
        color = QColor.fromHsv(color.hue(),
                               color.saturation() * 0.9,
                               color.value() * 0.95, color.alpha())
        for i in range(len(self.select_actions)):
            path = self.actions_settings[i].icon
            icon = create_icon(path, color)
            self.select_actions[i].setIcon(icon)

        icon = create_icon(":/plugins/multilayerselect/icons/deselectAll.svg",
                           color)
        self.deselect_all_action.setIcon(icon)

        icon = select_all_icon(color)
        self.select_all_action.setIcon(icon)

        icon = invert_selection_icon(color)
        self.invert_all_action.setIcon(icon)

        icon = expression_select_icon(color)
        self.select_by_expr_action.setIcon(icon)

    def on_settings_changed(self):
        """ Called when any setting has changed """
        if self.settings.value("show_settings", True, bool):
            self.toolbar.addAction(self.settings_action)
        else:
            self.toolbar.removeAction(self.settings_action)

        self.replace_default_action(
            self.settings.value("replace_actions", False, bool))

    def deselect_all(self):
        """ Deselect every feature """
        for layer in QgsProject.instance().mapLayers().values():
            if isinstance(layer, QgsVectorLayer):
                layer.removeSelection()
        update_status_message()

    def select_all(self):
        """ Select all the features from every vector layer """
        for layer in vector_layers():
            layer.selectAll()
        self.advanced_selection_tool_button.setDefaultAction(
            self.select_all_action)

        if self.embedded_advanced_tool_button:
            self.embedded_advanced_tool_button.setDefaultAction(
                self.select_all_action)

        update_status_message()

    def invert_all(self):
        """ Invert the selection of every vector layer """
        for layer in vector_layers():
            layer.invertSelection()
        self.advanced_selection_tool_button.setDefaultAction(
            self.invert_all_action)

        if self.embedded_advanced_tool_button:
            self.embedded_advanced_tool_button.setDefaultAction(
                self.invert_all_action)
        update_status_message()

    def select_by_expression(self):
        """ Create and open the Expression builder dialog"""

        if self.expression_dialog:
            self.expression_dialog.deleteLater()
        self.expression_dialog = MultiLayerSelectionExpressionBuilder()
        self.expression_dialog.show()

        self.advanced_selection_tool_button.setDefaultAction(
            self.select_by_expr_action)

        if self.embedded_advanced_tool_button:
            self.embedded_advanced_tool_button.setDefaultAction(
                self.select_by_expr_action)
        update_status_message()

    def replace_default_action(self, value):
        """Replace the default QGIS selection action with the multilayer ones

        Args:
            value (bool): If true, replace the actions, else put the multi actions
                inside their own toolbar
        """

        toolbar = self.iface.attributesToolBar()
        main_window = self.iface.mainWindow()
        main_window.findChild(QAction, "ActionSelect").setVisible(not value)
        main_window.findChild(QAction, "ActionSelection").setVisible(not value)
        main_window.findChild(QAction,
                              "mActionDeselectAll").setVisible(not value)

        actiontable = main_window.findChild(QAction, "mActionOpenTable")
        actionform = main_window.findChild(QAction, "mActionSelectByForm")

        # Remove the multi layer tool buttons from the QGIS attribute toolbar
        toolbar.removeAction(self.embedded_selection_tool_button_action)
        toolbar.removeAction(self.embedded_advanced_tool_button_action)

        if value:

            # Create the QToolButtons that will be added to the default toolbar
            self.embedded_selection_tool_button = QToolButton()
            self.embedded_selection_tool_button.setPopupMode(
                QToolButton.MenuButtonPopup)

            # Add selection tools action to the button (Rect, Polygon, Radius, Freehand)
            self.embedded_selection_tool_button.addActions(self.select_actions)
            self.embedded_selection_tool_button.setDefaultAction(
                self.select_actions[0])

            self.embedded_advanced_tool_button = QToolButton()
            self.embedded_advanced_tool_button.setPopupMode(
                QToolButton.MenuButtonPopup)

            # Add Invert, Select All, Select from value and Select from expressions
            self.embedded_advanced_tool_button.addAction(
                self.select_all_action)
            self.embedded_advanced_tool_button.setDefaultAction(
                self.select_all_action)
            self.embedded_advanced_tool_button.addAction(
                self.invert_all_action)
            self.embedded_advanced_tool_button.addAction(
                self.select_by_expr_action)
            self.embedded_advanced_tool_button.addAction(actionform)

            self.embedded_selection_tool_button_action = toolbar.insertWidget(
                actiontable, self.embedded_selection_tool_button)
            self.embedded_advanced_tool_button_action = toolbar.insertWidget(
                actiontable, self.embedded_advanced_tool_button)

            # Add the deselect all action
            toolbar.insertAction(actiontable, self.deselect_all_action)

            # If the settigns is enabled add the show settings action
            if self.settings.value("show_settings", True, bool):
                toolbar.insertAction(actiontable, self.settings_action)
            else:
                toolbar.removeAction(self.settings_action)
            self.toolbar.hide()

        else:

            # Remove the multi actions from the default toolbar, and show
            # the custom toolbar
            self.embedded_selection_tool_button = None
            self.embedded_advanced_tool_button = None
            toolbar.removeAction(self.deselect_all_action)
            toolbar.removeAction(self.settings_action)
            self.toolbar.show()
示例#2
0
class FullscreenableWidget(QMainWindow):
    widgetFullscreened = Signal(bool)

    def __init__(self, parent=None, icon_size=None):
        QMainWindow.__init__(self, parent)
        self.toolbar = QToolBar('tools', parent=self)
        self.toolbar.setContentsMargins(0, 0, 0, 0)
        self.icon_provider = IconProvider(self)
        self.dark_mode = self.icon_provider.get_theme_mode(self)
        if icon_size is not None:
            self.toolbar.setIconSize(QSize(icon_size, icon_size))
        self.addToolBar(Qt.RightToolBarArea, self.toolbar)

        self.action_fullscreen = QAction(self)
        self.action_fullscreen.setIcon(
            QIcon(self.icon_provider.get_icon_path('fullscreen.svg')))
        self.toolbar.addAction(self.action_fullscreen)
        self.action_windowed = QAction(self)
        self.action_windowed.setIcon(
            QIcon(self.icon_provider.get_icon_path('fullscreen_exit.svg')))
        # signalling:
        self.action_fullscreen.triggered.connect(self.go_fullscreen)
        self.action_windowed.triggered.connect(self.go_windowed)
        self.windowed_parent = None
        self.win_parent_layout = None
        self.index_in_layout = None
        self.windowed_flags = None
        self.windowed_geometry = None
        self.position_in_grid = None

    def go_fullscreen(self):
        self.windowed_flags = self.windowFlags()
        self.windowed_geometry = self.geometry()
        cur_scr = self.screen()  # to check which screen
        s_count = len(qApp.screens())
        for i in range(s_count):
            if qApp.screens()[i] == cur_scr:
                screen = qApp.screens()[i]
        if self.parent() is not None:
            self.windowed_parent = self.parent()
            self.win_parent_layout = self.windowed_parent.layout()
            self.index_in_layout = self.win_parent_layout.indexOf(self)
            if isinstance(self.win_parent_layout, QGridLayout):
                self.position_in_grid = \
                    self.win_parent_layout.getItemPosition(
                        self.index_in_layout)
            self.win_parent_layout.removeWidget(self)
        self.setParent(None)
        self.toolbar.insertAction(self.action_fullscreen, self.action_windowed)
        self.toolbar.removeAction(self.action_fullscreen)
        self.move(screen.geometry().x(), screen.geometry().y())
        self.showFullScreen()
        self.widgetFullscreened.emit(True)

    def go_windowed(self):
        self.showNormal()
        if self.windowed_parent is not None:
            if isinstance(self.win_parent_layout, (QBoxLayout, QSplitter)):
                self.win_parent_layout.insertWidget(self.index_in_layout, self)
            elif isinstance(self.win_parent_layout, QGridLayout):
                self.win_parent_layout.addWidget(self, *self.position_in_grid)
            self.setParent(self.windowed_parent)
            self.windowed_parent = None
        self.setGeometry(self.windowed_geometry)
        self.toolbar.insertAction(self.action_windowed, self.action_fullscreen)
        self.toolbar.removeAction(self.action_windowed)
        self.widgetFullscreened.emit(False)
示例#3
0
class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setup_ui()

        # UI connections
        self.action_open_amazon_view.triggered.connect(self.open_amazon)
        self.action_open_vendor_view.triggered.connect(self.open_vendor)
        self.action_open_operations.triggered.connect(self.open_operations)
        self.action_edit_vendors.triggered.connect(self.on_edit_vendors)

        self.tabs.tabCloseRequested.connect(self.close_tab)
        self.tabs.currentChanged.connect(self.tab_changed)

        self.current_tab = None

        # Set up the database connection.
        self.dbengine = create_engine('sqlite:///prowler.db')
        self.dbsession = Session(bind=self.dbengine)

        Base.metadata.create_all(self.dbengine)

        amazon = Vendor(id=0, name='Amazon', url='www.amazon.com')
        self.dbsession.add(self.dbsession.merge(amazon))
        self.dbsession.commit()

    def setup_ui(self):
        """Initialize the main window's UI components"""
        # Scale the window to the size of the screen
        desktop = QApplication.desktop()
        size = desktop.availableGeometry()

        self.resize(size.width() * .9, size.height() * .9)

        # Set up the toolbar
        self.toolBar = QToolBar(self)
        self.addToolBar(self.toolBar)

        # Create toolbar actions
        self.action_open_amazon_view = QAction(QIcon('icons/amazon.png'), 'Open Amazon view', self)
        self.action_open_vendor_view = QAction(QIcon('icons/folder.png'), 'Open Vendor view', self)
        self.action_open_operations = QAction(QIcon('icons/ops_view.png'), 'Open Operations', self)
        self.action_edit_vendors = QAction(QIcon('icons/vendor.png'), 'Edit vendors', self)

        # Add actions and separators to the toolbar
        self.toolBar.addActions([self.action_open_amazon_view,
                                self.action_open_vendor_view,
                                self.action_open_operations])

        self.toolBar.addSeparator()
        self.toolBar.addAction(self.action_edit_vendors)
        self.toolBar.addSeparator()

        # Create the central tab widget
        self.tabs = QTabWidget(self)
        self.tabs.setDocumentMode(True)
        self.tabs.setTabsClosable(True)

        self.setCentralWidget(self.tabs)

    def on_edit_vendors(self):
        """Show the Edit Vendors dialog."""
        dialog = EditVendorDialog(parent=self)
        dialog.exec()

    def open_amazon(self):
        """Open a new AmazonView."""
        view = AmazonView(self)
        idx = self.tabs.addTab(view, 'Amazon')
        self.tabs.setCurrentIndex(idx)

    def open_vendor(self):
        """Open a new VendorView."""
        view = VendorView(self)
        idx = self.tabs.addTab(view, 'Sources')
        self.tabs.setCurrentIndex(idx)

    def open_operations(self):
        """Open, or re-focus, the Operations view."""
        # We only want one operations view open at a time
        for i in range(self.tabs.count()):
            if isinstance(self.tabs.widget(i), OperationsView):
                self.tabs.setCurrentIndex(i)
                return

        view = OperationsView(self)
        idx = self.tabs.addTab(view, 'Operations')
        self.tabs.setCurrentIndex(idx)

    def close_tab(self, index):
        """Respond to a tabCloseRequested signal."""
        self.tabs.removeTab(index)

    def tab_changed(self, index):
        """Re-populate the toolbar with the actions specific to the new tab."""
        if self.current_tab:
            for action in self.current_tab.toolbar_actions:
                self.toolBar.removeAction(action)

        self.current_tab = self.tabs.currentWidget()

        if self.current_tab:
            for action in self.current_tab.toolbar_actions:
                self.toolBar.addAction(action)