class TimeSeriesView(QWidget):

    DEFAULT_ROW_HEIGHT = 150

    # Emitted when some styles have been updated
    styles_updated = pyqtSignal()

    def __init__(self, title=None, image_dir=None, parent=None):
        QWidget.__init__(self, parent)

        self.__toolbar = QToolBar()
        self.__scene = MyScene(0, 0, 600, 400)
        self.__view = TimeSeriesGraphicsView(self.__scene)
        self.__view.setAlignment(Qt.AlignLeft | Qt.AlignTop)

        self.__scene.sceneRectChanged.connect(self.on_rect_changed)

        if image_dir is None:
            image_dir = os.path.join(os.path.dirname(__file__), "img")

        self.__action_move_row_up = QAction(
            QIcon(os.path.join(image_dir, "up.svg")), "Move the row up",
            self.__toolbar)
        self.__action_move_row_up.triggered.connect(self.on_move_row_up)
        self.__action_move_row_down = QAction(
            QIcon(os.path.join(image_dir, "down.svg")), "Move the row down",
            self.__toolbar)
        self.__action_move_row_down.triggered.connect(self.on_move_row_down)

        self.__action_edit_style = QAction(
            QIcon(os.path.join(image_dir, "symbology.svg")), "Edit row style",
            self.__toolbar)
        self.__action_edit_style.triggered.connect(self.on_edit_style)

        self.__action_add_row = QAction(
            QIcon(os.path.join(image_dir, "add.svg")), "Add a data row",
            self.__toolbar)
        self.__action_add_row.triggered.connect(self.on_add_row)

        self.__action_remove_row = QAction(
            QIcon(os.path.join(image_dir, "remove.svg")), "Remove the row",
            self.__toolbar)
        self.__action_remove_row.triggered.connect(self.on_remove_row)

        self.__toolbar.addAction(self.__action_move_row_up)
        self.__toolbar.addAction(self.__action_move_row_down)
        self.__toolbar.addAction(self.__action_edit_style)
        self.__toolbar.addAction(self.__action_add_row)
        self.__toolbar.addAction(self.__action_remove_row)

        self.__title_label = QLabel()
        if title is not None:
            self.set_title(title)

        self.__status_bar = QStatusBar()

        vbox = QVBoxLayout()
        vbox.addWidget(self.__title_label)
        vbox.addWidget(self.__toolbar)
        vbox.addWidget(self.__view)
        vbox.addWidget(self.__status_bar)
        self.setLayout(vbox)

        self.__station_id = None
        # (log_item, legend_item) for each row
        self.__rows = []
        # { layer : (log_item, legend_item) }
        self.__data2logitems = {}
        self.__row_heights = []

        self._min_x = None
        self._max_x = None

        self.__allow_mouse_translation = True
        self.__translation_orig = None

        self.__style_dir = os.path.join(os.path.dirname(__file__), 'styles')

        self.select_row(-1)

        self._update_row_depths()

    def on_rect_changed(self, rect):
        for item, _ in self.__rows:
            item.set_width(rect.width())

    def set_title(self, title):
        self.__title_label.setText(title)

    def _place_items(self):
        y = 0
        for i, r in enumerate(self.__rows):
            item, legend = r
            height = self.__row_heights[i]
            legend.setPos(0, y)
            item.setPos(legend.boundingRect().width(), y)
            y += height

        rect = self.__scene.sceneRect()
        rect.setHeight(y)
        self.__scene.setSceneRect(rect)

    def _add_row(self, log_item, legend_item):
        self.__scene.addItem(log_item)
        self.__scene.addItem(legend_item)

        log_item.set_min_depth(self._min_x)
        log_item.set_max_depth(self._max_x)
        self.__rows.insert(0, (log_item, legend_item))
        self.__row_heights.insert(0, log_item.boundingRect().height())

        self._place_items()

    def set_x_range(self, min_x, max_x):
        self._min_x, self._max_x = min_x, max_x
        self._update_row_depths()

    def _update_row_depths(self):
        if self._min_x is None:
            return
        for item, _ in self.__rows:
            item.set_min_depth(self._min_x)
            item.set_max_depth(self._max_x)
            item.update()

    def remove_data_row(self, data):
        """Remove data row from widget

        :param data: data to be removed
        """

        # Row doesn't exist
        if data not in self.__data2logitems:
            raise ValueError("Impossible to remove data row : given data"
                             " object doesn't exist")

        log_item, legend_item = self.__data2logitems[data]
        for i, (pitem, litem) in enumerate(self.__rows):
            if pitem == log_item and litem == legend_item:
                self.__rows.pop(i)
                self.__row_widths.pop(i)
                del self.__data2logitems[data]
                self.__scene.removeItem(log_item)
                self.__scene.removeItem(legend_item)
                return

        # Rows not found
        assert False

    def clear_data_rows(self):
        # remove item from scenes
        for (item, legend) in self.__rows:
            self.__scene.removeItem(legend)
            self.__scene.removeItem(item)

        # remove from internal lists
        self.__rows = []
        self.__rows_widths = []
        self.__data2logitems = {}

        self.select_row(-1)
        self._place_items()
        self._update_button_visibility()

        self.add_time_scale()

    def on_plot_tooltip(self, station_name, txt):
        if station_name is not None:
            self.__status_bar.showMessage(
                u"Station: {} ".format(station_name) + txt)
        else:
            self.__status_bar.showMessage(txt)

    def add_data_row(self, data, title, uom, station_name=None, config=None):
        """
        Parameters
        ----------
        data: ??
        title: str
        uom: str
          Unit of measure
        station_name: str
          Station name
        config: PlotConfig
        """
        symbology, symbology_type = config.get_symbology()

        plot_item = PlotItem(size=QSizeF(self.__scene.width(),
                                         self.DEFAULT_ROW_HEIGHT),
                             render_type=POINT_RENDERER
                             if not symbology_type else symbology_type,
                             symbology=symbology,
                             x_orientation=ORIENTATION_LEFT_TO_RIGHT,
                             y_orientation=ORIENTATION_UPWARD)
        plot_item.style_updated.connect(self.styles_updated)

        plot_item.set_layer(data.get_layer())
        plot_item.tooltipRequested.connect(
            lambda txt: self.on_plot_tooltip(station_name, txt))

        legend_item = LegendItem(self.DEFAULT_ROW_HEIGHT,
                                 title,
                                 unit_of_measure=uom,
                                 is_vertical=True)
        data.data_modified.connect(
            lambda data=data: self._update_data_row(data, config))

        # center on new data
        self._min_x, self._max_x = data.get_x_min(), data.get_x_max()
        # if we have only one value, center it on a 2 minutes range
        if self._min_x and self._min_x == self._max_x:
            self._min_x -= 60
            self._max_x += 60

        self.__data2logitems[data] = (plot_item, legend_item)
        self._add_row(plot_item, legend_item)
        self._update_data_row(data, config)
        self._update_row_depths()

    def add_time_scale(self, title="Time"):
        scale_item = TimeScaleItem(self.__scene.width(),
                                   self.DEFAULT_ROW_HEIGHT * 3 / 4,
                                   self._min_x, self._max_x)
        legend_item = LegendItem(self.DEFAULT_ROW_HEIGHT * 3 / 4,
                                 title,
                                 is_vertical=True)
        self._add_row(scale_item, legend_item)

    def _update_data_row(self, data, config):

        plot_item, legend_item = self.__data2logitems[data]

        y_values = data.get_y_values()
        x_values = data.get_x_values()
        if y_values is None or x_values is None:
            plot_item.set_data_window(None)
            return

        plot_item.set_data(data.get_x_values(), data.get_y_values())
        win = plot_item.data_window()
        min_x, min_y, max_x, max_y = win.left(), win.top(), win.right(
        ), win.bottom()

        if config and config.get("min") is not None:
            min_y = float(config['min'])
        if config and config.get("max") is not None:
            max_y = float(config['max'])

        # legend
        legend_item.set_scale(min_y, max_y)
        plot_item.set_data_window(
            QRectF(min_x, min_y, max_x - min_x, max_y - min_y))

        self.__scene.update()

    def select_row_at(self, pos):
        y = pos.y()
        r = 0
        selected = -1
        for i, height in enumerate(self.__row_heights):
            if y >= r and y < r + height:
                selected = i
                break
            r += height
        self.select_row(selected)

    def select_row(self, idx):
        self.__selected_row = idx
        for i, p in enumerate(self.__rows):
            item, legend = p
            item.set_selected(idx == i)
            legend.set_selected(idx == i)
            item.update()
            legend.update()

        self._update_button_visibility()

    def _update_button_visibility(self):
        idx = self.__selected_row
        self.__action_move_row_up.setEnabled(idx != -1 and idx > 0)
        self.__action_move_row_down.setEnabled(idx != -1
                                               and idx < len(self.__rows) - 1)
        self.__action_edit_style.setEnabled(idx != -1)
        self.__action_remove_row.setEnabled(idx != -1)

    def on_move_row_up(self):
        if self.__selected_row < 1:
            return

        sel = self.__selected_row
        self.__rows[sel -
                    1], self.__rows[sel] = self.__rows[sel], self.__rows[sel -
                                                                         1]
        self.__row_heights[sel - 1], self.__row_heights[
            sel] = self.__row_heights[sel], self.__row_heights[sel - 1]
        self.__selected_row -= 1
        self._place_items()
        self._update_button_visibility()

    def on_move_row_down(self):
        if self.__selected_row == -1 or self.__selected_row >= len(
                self.__rows) - 1:
            return

        sel = self.__selected_row
        self.__rows[sel +
                    1], self.__rows[sel] = self.__rows[sel], self.__rows[sel +
                                                                         1]
        self.__row_heights[sel + 1], self.__row_heights[
            sel] = self.__row_heights[sel], self.__row_heights[sel + 1]
        self.__selected_row += 1
        self._place_items()
        self._update_button_visibility()

    def on_remove_row(self):
        if self.__selected_row == -1:
            return

        sel = self.__selected_row

        # remove item from scenes
        item, legend = self.__rows[sel]
        self.__scene.removeItem(legend)
        self.__scene.removeItem(item)

        # remove from internal list
        del self.__rows[sel]
        del self.__row_heights[sel]
        self.__selected_row = -1
        self._place_items()
        self._update_button_visibility()

    def on_edit_style(self):
        if self.__selected_row == -1:
            return

        item = self.__rows[self.__selected_row][0]
        item.edit_style()

    def on_add_row(self):
        # to be overridden by subclasses
        pass
    def __init__(self, title=None, image_dir=None, parent=None):
        QWidget.__init__(self, parent)

        self.__toolbar = QToolBar()
        self.__scene = MyScene(0, 0, 600, 400)
        self.__view = TimeSeriesGraphicsView(self.__scene)
        self.__view.setAlignment(Qt.AlignLeft | Qt.AlignTop)

        self.__scene.sceneRectChanged.connect(self.on_rect_changed)

        if image_dir is None:
            image_dir = os.path.join(os.path.dirname(__file__), "img")

        self.__action_move_row_up = QAction(
            QIcon(os.path.join(image_dir, "up.svg")), "Move the row up",
            self.__toolbar)
        self.__action_move_row_up.triggered.connect(self.on_move_row_up)
        self.__action_move_row_down = QAction(
            QIcon(os.path.join(image_dir, "down.svg")), "Move the row down",
            self.__toolbar)
        self.__action_move_row_down.triggered.connect(self.on_move_row_down)

        self.__action_edit_style = QAction(
            QIcon(os.path.join(image_dir, "symbology.svg")), "Edit row style",
            self.__toolbar)
        self.__action_edit_style.triggered.connect(self.on_edit_style)

        self.__action_add_row = QAction(
            QIcon(os.path.join(image_dir, "add.svg")), "Add a data row",
            self.__toolbar)
        self.__action_add_row.triggered.connect(self.on_add_row)

        self.__action_remove_row = QAction(
            QIcon(os.path.join(image_dir, "remove.svg")), "Remove the row",
            self.__toolbar)
        self.__action_remove_row.triggered.connect(self.on_remove_row)

        self.__toolbar.addAction(self.__action_move_row_up)
        self.__toolbar.addAction(self.__action_move_row_down)
        self.__toolbar.addAction(self.__action_edit_style)
        self.__toolbar.addAction(self.__action_add_row)
        self.__toolbar.addAction(self.__action_remove_row)

        self.__title_label = QLabel()
        if title is not None:
            self.set_title(title)

        self.__status_bar = QStatusBar()

        vbox = QVBoxLayout()
        vbox.addWidget(self.__title_label)
        vbox.addWidget(self.__toolbar)
        vbox.addWidget(self.__view)
        vbox.addWidget(self.__status_bar)
        self.setLayout(vbox)

        self.__station_id = None
        # (log_item, legend_item) for each row
        self.__rows = []
        # { layer : (log_item, legend_item) }
        self.__data2logitems = {}
        self.__row_heights = []

        self._min_x = None
        self._max_x = None

        self.__allow_mouse_translation = True
        self.__translation_orig = None

        self.__style_dir = os.path.join(os.path.dirname(__file__), 'styles')

        self.select_row(-1)

        self._update_row_depths()
Exemple #3
0
    def setupUi(self):
        self.setWindowTitle(self.tr("DB Manager"))
        self.setWindowIcon(QIcon(":/db_manager/icon"))
        self.resize(QSize(700, 500).expandedTo(self.minimumSizeHint()))

        # create central tab widget and add the first 3 tabs: info, table and preview
        self.tabs = QTabWidget()
        self.info = InfoViewer(self)
        self.tabs.addTab(self.info, self.tr("Info"))
        self.table = TableViewer(self)
        self.tabs.addTab(self.table, self.tr("Table"))
        self.preview = LayerPreview(self)
        self.tabs.addTab(self.preview, self.tr("Preview"))
        self.setCentralWidget(self.tabs)

        # display close button for all tabs but the first 3 ones, i.e.
        # HACK: just hide the close button where not needed (GS)
        self.tabs.setTabsClosable(True)
        self.tabs.tabCloseRequested.connect(self.close_tab)
        tabbar = self.tabs.tabBar()
        for i in range(3):
            btn = tabbar.tabButton(i, QTabBar.RightSide) if tabbar.tabButton(i, QTabBar.RightSide) else tabbar.tabButton(i, QTabBar.LeftSide)
            btn.resize(0, 0)
            btn.hide()

        # Creates layout for message bar
        self.layout = QGridLayout(self.info)
        self.layout.setContentsMargins(0, 0, 0, 0)
        spacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        self.layout.addItem(spacerItem, 1, 0, 1, 1)
        # init messageBar instance
        self.infoBar = QgsMessageBar(self.info)
        sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.infoBar.setSizePolicy(sizePolicy)
        self.layout.addWidget(self.infoBar, 0, 0, 1, 1)

        # create database tree
        self.dock = QDockWidget("Tree", self)
        self.dock.setObjectName("DB_Manager_DBView")
        self.dock.setFeatures(QDockWidget.DockWidgetMovable)
        self.tree = DBTree(self)
        self.dock.setWidget(self.tree)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.dock)

        # create status bar
        self.statusBar = QStatusBar(self)
        self.setStatusBar(self.statusBar)

        # create menus
        self.menuBar = QMenuBar(self)
        self.menuDb = QMenu(self.tr("&Database"), self)
        self.menuBar.addMenu(self.menuDb)
        self.menuSchema = QMenu(self.tr("&Schema"), self)
        actionMenuSchema = self.menuBar.addMenu(self.menuSchema)
        self.menuTable = QMenu(self.tr("&Table"), self)
        actionMenuTable = self.menuBar.addMenu(self.menuTable)
        self.menuHelp = None  # QMenu(self.tr("&Help"), self)
        # actionMenuHelp = self.menuBar.addMenu(self.menuHelp)

        self.setMenuBar(self.menuBar)

        # create toolbar
        self.toolBar = QToolBar("Default", self)
        self.toolBar.setObjectName("DB_Manager_ToolBar")
        self.addToolBar(self.toolBar)

        # create menus' actions

        # menu DATABASE
        sep = self.menuDb.addSeparator()
        sep.setObjectName("DB_Manager_DbMenu_placeholder")
        sep.setVisible(False)

        self.actionRefresh = self.menuDb.addAction(QIcon(":/db_manager/actions/refresh"), self.tr("&Refresh"),
                                                   self.refreshActionSlot, QKeySequence("F5"))
        self.actionSqlWindow = self.menuDb.addAction(QIcon(":/db_manager/actions/sql_window"), self.tr("&SQL window"),
                                                     self.runSqlWindow, QKeySequence("F2"))
        self.menuDb.addSeparator()
        self.actionClose = self.menuDb.addAction(QIcon(), self.tr("&Exit"), self.close, QKeySequence("CTRL+Q"))

        # menu SCHEMA
        sep = self.menuSchema.addSeparator()
        sep.setObjectName("DB_Manager_SchemaMenu_placeholder")
        sep.setVisible(False)

        actionMenuSchema.setVisible(False)

        # menu TABLE
        sep = self.menuTable.addSeparator()
        sep.setObjectName("DB_Manager_TableMenu_placeholder")
        sep.setVisible(False)

        self.actionImport = self.menuTable.addAction(QIcon(":/db_manager/actions/import"),
                                                     self.tr("&Import layer/file"), self.importActionSlot)
        self.actionExport = self.menuTable.addAction(QIcon(":/db_manager/actions/export"), self.tr("&Export to file"),
                                                     self.exportActionSlot)
        self.menuTable.addSeparator()
        #self.actionShowSystemTables = self.menuTable.addAction(self.tr("Show system tables/views"), self.showSystemTables)
        #self.actionShowSystemTables.setCheckable(True)
        #self.actionShowSystemTables.setChecked(True)
        actionMenuTable.setVisible(False)

        # add actions to the toolbar
        self.toolBar.addAction(self.actionRefresh)
        self.toolBar.addAction(self.actionSqlWindow)
        self.toolBar.addAction(self.actionImport)
        self.toolBar.addAction(self.actionExport)
Exemple #4
0
    def __init__(self, title=None,image_dir=None, parent=None):
        QWidget.__init__(self, parent)

        self.toolbar = QToolBar()
        self.__log_scene = MyScene(0, 0, 600, 600)
        self.__log_view = LogGraphicsView(self.__log_scene)
        self.__log_view.setAlignment(Qt.AlignLeft|Qt.AlignTop)

        self.__log_scene.sceneRectChanged.connect(self.on_rect_changed)

        if image_dir is None:
            image_dir = os.path.join(os.path.dirname(__file__), "img")

        self.__action_move_column_left = QAction(QIcon(os.path.join(image_dir, "left.svg")), "Move the column to the left", self.toolbar)
        self.__action_move_column_left.triggered.connect(self.on_move_column_left)
        self.__action_move_column_right = QAction(QIcon(os.path.join(image_dir, "right.svg")), "Move the column to the right", self.toolbar)
        self.__action_move_column_right.triggered.connect(self.on_move_column_right)

        self.__action_edit_style = QAction(QIcon(os.path.join(image_dir, "symbology.svg")), "Edit column style", self.toolbar)
        self.__action_edit_style.triggered.connect(self.on_edit_style)

        self.__action_add_column = QAction(QIcon(os.path.join(image_dir, "add.svg")), "Add a data column from configured ones", self.toolbar)
        self.__action_add_column.triggered.connect(self.on_add_column)

        self.__action_remove_column = QAction(QIcon(os.path.join(image_dir, "remove.svg")), "Remove the column", self.toolbar)
        self.__action_remove_column.triggered.connect(self.on_remove_column)

        #self.__action_move_content_right = QAction("Move content right", self.toolbar)
        #self.__action_move_content_left = QAction("Move content left", self.toolbar)
        #self.__action_move_content_left.triggered.connect(self.on_move_content_left)
        #self.__action_move_content_right.triggered.connect(self.on_move_content_right)

        self.toolbar.addAction(self.__action_move_column_left)
        self.toolbar.addAction(self.__action_move_column_right)
        self.toolbar.addAction(self.__action_edit_style)
        self.toolbar.addAction(self.__action_add_column)
        self.toolbar.addAction(self.__action_remove_column)

        #self.__toolbar.addAction(self.__action_move_content_left)
        #self.__toolbar.addAction(self.__action_move_content_right)

        self.__title_label = QLabel()
        if title is not None:
            self.set_title(title)

        self.__status_bar = QStatusBar()

        vbox = QVBoxLayout()
        vbox.addWidget(self.__title_label)
        vbox.addWidget(self.toolbar)
        vbox.addWidget(self.__log_view)
        vbox.addWidget(self.__status_bar)
        self.setLayout(vbox)

        self.__station_id = None
        # (log_item, legend_item) for each column
        self.__columns = []
        # { layer : (log_item, legend_item) }
        self.__data2logitems = {}
        self.__column_widths = []

        self._min_z = 0
        self._max_z = 40

        self.__allow_mouse_translation = True
        self.__translation_orig = None

        self.__style_dir = os.path.join(os.path.dirname(__file__),
                                        'styles')

        self.select_column(-1)

        # by default we have a Z scale
        self.add_z_scale()
Exemple #5
0
class WellLogView(QWidget):

    DEFAULT_COLUMN_WIDTH = 150

    # Emitted when some styles have been updated
    styles_updated = pyqtSignal()

    def __init__(self, title=None,image_dir=None, parent=None):
        QWidget.__init__(self, parent)

        self.toolbar = QToolBar()
        self.__log_scene = MyScene(0, 0, 600, 600)
        self.__log_view = LogGraphicsView(self.__log_scene)
        self.__log_view.setAlignment(Qt.AlignLeft|Qt.AlignTop)

        self.__log_scene.sceneRectChanged.connect(self.on_rect_changed)

        if image_dir is None:
            image_dir = os.path.join(os.path.dirname(__file__), "img")

        self.__action_move_column_left = QAction(QIcon(os.path.join(image_dir, "left.svg")), "Move the column to the left", self.toolbar)
        self.__action_move_column_left.triggered.connect(self.on_move_column_left)
        self.__action_move_column_right = QAction(QIcon(os.path.join(image_dir, "right.svg")), "Move the column to the right", self.toolbar)
        self.__action_move_column_right.triggered.connect(self.on_move_column_right)

        self.__action_edit_style = QAction(QIcon(os.path.join(image_dir, "symbology.svg")), "Edit column style", self.toolbar)
        self.__action_edit_style.triggered.connect(self.on_edit_style)

        self.__action_add_column = QAction(QIcon(os.path.join(image_dir, "add.svg")), "Add a data column from configured ones", self.toolbar)
        self.__action_add_column.triggered.connect(self.on_add_column)

        self.__action_remove_column = QAction(QIcon(os.path.join(image_dir, "remove.svg")), "Remove the column", self.toolbar)
        self.__action_remove_column.triggered.connect(self.on_remove_column)

        #self.__action_move_content_right = QAction("Move content right", self.toolbar)
        #self.__action_move_content_left = QAction("Move content left", self.toolbar)
        #self.__action_move_content_left.triggered.connect(self.on_move_content_left)
        #self.__action_move_content_right.triggered.connect(self.on_move_content_right)

        self.toolbar.addAction(self.__action_move_column_left)
        self.toolbar.addAction(self.__action_move_column_right)
        self.toolbar.addAction(self.__action_edit_style)
        self.toolbar.addAction(self.__action_add_column)
        self.toolbar.addAction(self.__action_remove_column)

        #self.__toolbar.addAction(self.__action_move_content_left)
        #self.__toolbar.addAction(self.__action_move_content_right)

        self.__title_label = QLabel()
        if title is not None:
            self.set_title(title)

        self.__status_bar = QStatusBar()

        vbox = QVBoxLayout()
        vbox.addWidget(self.__title_label)
        vbox.addWidget(self.toolbar)
        vbox.addWidget(self.__log_view)
        vbox.addWidget(self.__status_bar)
        self.setLayout(vbox)

        self.__station_id = None
        # (log_item, legend_item) for each column
        self.__columns = []
        # { layer : (log_item, legend_item) }
        self.__data2logitems = {}
        self.__column_widths = []

        self._min_z = 0
        self._max_z = 40

        self.__allow_mouse_translation = True
        self.__translation_orig = None

        self.__style_dir = os.path.join(os.path.dirname(__file__),
                                        'styles')

        self.select_column(-1)

        # by default we have a Z scale
        self.add_z_scale()
        
    def on_rect_changed(self, rect):
        for item, _ in self.__columns:
            item.set_height(rect.height())

    def set_title(self, title):
        self.__title_label.setText(title)

    def _place_items(self):
        x = 0
        for i, c in enumerate(self.__columns):
            item, legend = c
            width = self.__column_widths[i]
            legend.setPos(x, 0)
            item.setPos(x, legend.boundingRect().height())
            x += width

        rect = self.__log_scene.sceneRect()
        rect.setWidth(x)
        self.__log_scene.setSceneRect(rect)

    def _add_column(self, log_item, legend_item):
        self.__log_scene.addItem(log_item)
        self.__log_scene.addItem(legend_item)

        log_item.set_min_depth(self._min_z)
        log_item.set_max_depth(self._max_z)
        self.__columns.append((log_item, legend_item))
        self.__column_widths.append(log_item.boundingRect().width())

        self._place_items()

    def _fit_to_max_depth(self):
        self._min_z = min([i.min_depth() for i, _ in self.__columns if i.min_depth() is not None])
        self._max_z = max([i.max_depth() for i, _ in self.__columns if i.max_depth() is not None])
        # if we have only one value, center it on a 2 meters range
        if self._min_z == self._max_z:
            self._min_z -= 1.0
            self._max_z += 1.0

    def _update_column_depths(self):
        for item, _ in self.__columns:
            item.set_min_depth(self._min_z)
            item.set_max_depth(self._max_z)
            item.update()

    def add_z_scale(self, title="Depth"):
        scale_item = ZScaleItem(self.DEFAULT_COLUMN_WIDTH / 2, self.__log_scene.height(), self._min_z, self._max_z)
        legend_item = LegendItem(self.DEFAULT_COLUMN_WIDTH / 2, title, unit_of_measure="m")
        self._add_column(scale_item, legend_item)

    def remove_data_column(self, data):
        """Remove data column from widget

        :param data: data to be removed
        """

        # Column doesn't exist
        if data not in self.__data2logitems:
            raise ValueError("Impossible to remove data column : given data"
                             " object doesn't exist")

        log_item, legend_item = self.__data2logitems[data]
        for i, (pitem, litem) in enumerate(self.__columns):
            if pitem == log_item and litem == legend_item:
                self.__columns.pop(i)
                self.__column_widths.pop(i)
                del self.__data2logitems[data]
                self.__log_scene.removeItem(log_item)
                self.__log_scene.removeItem(legend_item)
                return

        # Columns not found
        assert False

    def clear_data_columns(self):
        # remove item from scenes
        for (item, legend) in self.__columns:
            self.__log_scene.removeItem(legend)
            self.__log_scene.removeItem(item)

        # remove from internal lists
        self.__columns = []
        self.__column_widths = []
        self.__data2logitems = {}
        
        self.__selected_column = -1
        self._place_items()
        self._update_button_visibility()

        # still add z scale
        self.add_z_scale()

    def on_plot_tooltip(self, txt, station_name = None):
        if station_name is not None:
            self.__status_bar.showMessage(u"Station: {} ".format(station_name) + txt)
        else:
            self.__status_bar.showMessage(txt)

    def add_data_column(self, data, title, uom, station_name = None, config = None):
        """
        Parameters
        ----------
        data: ??
        title: str
        uom: str
          Unit of measure
        station_name: str
          Station name
        config: PlotConfig
        """
        symbology, symbology_type = config.get_symbology()
        
        plot_item = PlotItem(size=QSizeF(self.DEFAULT_COLUMN_WIDTH, self.__log_scene.height()),
                             render_type = POLYGON_RENDERER if symbology_type is None else symbology_type,
                             symbology = symbology,
                             x_orientation = ORIENTATION_DOWNWARD,
                             y_orientation = ORIENTATION_LEFT_TO_RIGHT)
        plot_item.style_updated.connect(self.styles_updated)

        plot_item.set_layer(data.get_layer())
        plot_item.tooltipRequested.connect(lambda txt: self.on_plot_tooltip(txt, station_name))

        legend_item = LegendItem(self.DEFAULT_COLUMN_WIDTH, title, unit_of_measure=uom)
        data.data_modified.connect(lambda data=data : self._update_data_column(data, config))

        self.__data2logitems[data] = (plot_item, legend_item)
        self._add_column(plot_item, legend_item)
        self._update_data_column(data, config)
        self._update_column_depths()

    def _update_data_column(self, data, config):

        plot_item, legend_item = self.__data2logitems[data]

        y_values = data.get_y_values()
        x_values = data.get_x_values()
        if y_values is None or x_values is None:
            plot_item.set_data_window(None)
            return

        plot_item.set_data(data.get_x_values(), data.get_y_values())
        win = plot_item.data_window()
        min_x, min_y, max_x, max_y = win.left(), win.top(), win.right(), win.bottom()

        if config and config.get('min') is not None:
            min_y = float(config['min'])
        if config and config.get('max') is not None:
            max_y = float(config['max'])

        # legend
        legend_item.set_scale(min_y, max_y)
        plot_item.set_data_window(QRectF(min_x, min_y, max_x-min_x, max_y-min_y))

        self.__log_scene.update()

    def add_stratigraphy(self, layer, filter_expression, column_mapping, title, style_file=None, config=None):
        """Add stratigraphy data

        Parameters
        ----------
        layer: QgsVectorLayer
          The layer where stratigraphic data are stored
        filter_expression: str
          A QGIS expression to filter the vector layer
        column_mapping: dict
          Dictionary of column names
        title: str
          Title of the graph
        style_file: str
          Name of the style file to use
        config: PlotConfig
        """
        symbology = config.get_symbology()[0] if config else None
        item = StratigraphyItem(self.DEFAULT_COLUMN_WIDTH,
                                self.__log_scene.height(),
                                style_file=style_file if not symbology else None,
                                symbology=symbology,
                                column_mapping=column_mapping
        )
        item.style_updated.connect(self.styles_updated)
        legend_item = LegendItem(self.DEFAULT_COLUMN_WIDTH, title)

        item.set_layer(layer)
        item.tooltipRequested.connect(self.on_plot_tooltip)

        req = QgsFeatureRequest()
        req.setFilterExpression(filter_expression)
        item.set_data(list(layer.getFeatures(req)))

        self._add_column(item, legend_item)

    def add_imagery(self, image_filename, title, depth_from, depth_to):
        item = ImageryDataItem(self.DEFAULT_COLUMN_WIDTH,
                               self.__log_scene.height(),
                               image_filename,
                               depth_from,
                               depth_to)
        
        legend_item = LegendItem(self.DEFAULT_COLUMN_WIDTH, title)

        self._add_column(item, legend_item)

    def select_column_at(self, pos):
        x = pos.x()
        c = 0
        selected = -1
        for i, width in enumerate(self.__column_widths):
            if x >= c and x < c + width:
                selected = i
                break
            c += width
        self.select_column(selected)

    def select_column(self, idx):
        self.__selected_column = idx
        for i, p in enumerate(self.__columns):
            item, legend = p
            item.set_selected(idx == i)
            legend.set_selected(idx == i)
            item.update()
            legend.update()

        self._update_button_visibility()

    def selected_column(self):
        return self.__selected_column

    def _update_button_visibility(self):
        idx = self.__selected_column
        self.__action_move_column_left.setEnabled(idx != -1 and idx > 0)
        self.__action_move_column_right.setEnabled(idx != -1 and idx < len(self.__columns) - 1)

        item = self.__columns[idx][0] if idx > 0 else None
        self.__action_edit_style.setEnabled(bool(item and not isinstance(item, ImageryDataItem)))
        self.__action_remove_column.setEnabled(idx != -1)

    def on_move_column_left(self):
        if self.__selected_column < 1:
            return

        sel = self.__selected_column
        self.__columns[sel-1], self.__columns[sel] = self.__columns[sel], self.__columns[sel-1]
        self.__column_widths[sel-1], self.__column_widths[sel] = self.__column_widths[sel], self.__column_widths[sel-1]
        self.__selected_column -= 1
        self._place_items()
        self._update_button_visibility()

    def on_move_column_right(self):
        if self.__selected_column == -1 or self.__selected_column >= len(self.__columns) - 1:
            return

        sel = self.__selected_column
        self.__columns[sel+1], self.__columns[sel] = self.__columns[sel], self.__columns[sel+1]
        self.__column_widths[sel+1], self.__column_widths[sel] = self.__column_widths[sel], self.__column_widths[sel+1]
        self.__selected_column += 1
        self._place_items()
        self._update_button_visibility()

    def on_remove_column(self):
        if self.__selected_column == -1:
            return

        sel = self.__selected_column

        # remove item from scenes
        item, legend = self.__columns[sel]
        self.__log_scene.removeItem(legend)
        self.__log_scene.removeItem(item)

        # remove from internal list
        del self.__columns[sel]
        del self.__column_widths[sel]
        self.__selected_column = -1
        self._place_items()
        self._update_button_visibility()

    def on_edit_style(self):
        if self.__selected_column == -1:
            return

        item = self.__columns[self.__selected_column][0]
        item.edit_style()

    def on_add_column(self):
        # to be overridden by subclasses
        pass

    def styles(self):
        """Return the current style of each item"""
        return dict([(item.layer().id(), item.qgis_style())
                     for item, legend in self.__columns
                     if hasattr(item, "qgis_style")])
Exemple #6
0
class WellLogView(QWidget):

    DEFAULT_COLUMN_WIDTH = 150

    def __init__(self, title=None, image_dir=None, parent=None):
        QWidget.__init__(self, parent)

        toolbar = QToolBar()
        self.__log_scene = MyScene(0, 0, 600, 600)
        self.__log_view = LogGraphicsView(self.__log_scene)
        self.__log_view.setAlignment(Qt.AlignLeft | Qt.AlignTop)

        self.__log_scene.sceneRectChanged.connect(self.on_rect_changed)

        if image_dir is None:
            image_dir = os.path.join(os.path.dirname(__file__), "img")

        self.__action_move_column_left = QAction(
            QIcon(os.path.join(image_dir, "left.svg")),
            "Move the column to the left", toolbar)
        self.__action_move_column_left.triggered.connect(
            self.on_move_column_left)
        self.__action_move_column_right = QAction(
            QIcon(os.path.join(image_dir, "right.svg")),
            "Move the column to the right", toolbar)
        self.__action_move_column_right.triggered.connect(
            self.on_move_column_right)

        self.__action_edit_style = QAction(
            QIcon(os.path.join(image_dir, "symbology.svg")),
            "Edit column style", toolbar)
        self.__action_edit_style.triggered.connect(self.on_edit_style)

        self.__action_add_column = QAction(
            QIcon(os.path.join(image_dir, "add.svg")), "Add a data column",
            toolbar)
        self.__action_add_column.triggered.connect(self.on_add_column)

        self.__action_remove_column = QAction(
            QIcon(os.path.join(image_dir, "remove.svg")), "Remove the column",
            toolbar)
        self.__action_remove_column.triggered.connect(self.on_remove_column)

        #self.__action_move_content_right = QAction("Move content right", toolbar)
        #self.__action_move_content_left = QAction("Move content left", toolbar)
        #self.__action_move_content_left.triggered.connect(self.on_move_content_left)
        #self.__action_move_content_right.triggered.connect(self.on_move_content_right)

        toolbar.addAction(self.__action_move_column_left)
        toolbar.addAction(self.__action_move_column_right)
        toolbar.addAction(self.__action_edit_style)
        toolbar.addAction(self.__action_add_column)
        toolbar.addAction(self.__action_remove_column)

        #self.__toolbar.addAction(self.__action_move_content_left)
        #self.__toolbar.addAction(self.__action_move_content_right)

        self.__title_label = QLabel()
        if title is not None:
            self.set_title(title)

        self.__status_bar = QStatusBar()

        vbox = QVBoxLayout()
        vbox.addWidget(self.__title_label)
        vbox.addWidget(toolbar)
        vbox.addWidget(self.__log_view)
        vbox.addWidget(self.__status_bar)
        self.setLayout(vbox)

        self.__station_id = None
        # (log_item, legend_item) for each column
        self.__columns = []
        # { layer : (log_item, legend_item) }
        self.__data2logitems = {}
        self.__column_widths = []

        self._min_z = 0
        self._max_z = 40

        self.__allow_mouse_translation = True
        self.__translation_orig = None

        self.__style_dir = os.path.join(os.path.dirname(__file__), 'styles')

        self.select_column(-1)

        # by default we have a Z scale
        self.add_z_scale()

    def on_rect_changed(self, rect):
        for item, _ in self.__columns:
            item.set_height(rect.height())

    def set_title(self, title):
        self.__title_label.setText(title)

    def _place_items(self):
        x = 0
        for i, c in enumerate(self.__columns):
            item, legend = c
            width = self.__column_widths[i]
            legend.setPos(x, 0)
            item.setPos(x, legend.boundingRect().height())
            x += width
        self.__log_view.setMinimumSize(x,
                                       self.__log_view.minimumSize().height())

    def _add_column(self, log_item, legend_item):
        self.__log_scene.addItem(log_item)
        self.__log_scene.addItem(legend_item)

        log_item.set_min_depth(self._min_z)
        log_item.set_max_depth(self._max_z)
        self.__columns.append((log_item, legend_item))
        self.__column_widths.append(log_item.boundingRect().width())

        self._place_items()

    def _fit_to_max_depth(self):
        self._min_z = min([
            i.min_depth() for i, _ in self.__columns
            if i.min_depth() is not None
        ])
        self._max_z = max([
            i.max_depth() for i, _ in self.__columns
            if i.max_depth() is not None
        ])
        # if we have only one value, center it on a 2 meters range
        if self._min_z == self._max_z:
            self._min_z -= 1.0
            self._max_z += 1.0

    def _update_column_depths(self):
        for item, _ in self.__columns:
            item.set_min_depth(self._min_z)
            item.set_max_depth(self._max_z)
            item.update()

    def add_z_scale(self, title="Depth"):
        scale_item = ZScaleItem(self.DEFAULT_COLUMN_WIDTH / 2,
                                self.__log_scene.height(), self._min_z,
                                self._max_z)
        legend_item = LegendItem(self.DEFAULT_COLUMN_WIDTH / 2,
                                 title,
                                 unit_of_measure="m")
        self._add_column(scale_item, legend_item)

    def remove_data_column(self, data):
        """Remove data column from widget

        :param data: data to be removed
        """

        # Column doesn't exist
        if data not in self.__data2logitems:
            raise ValueError("Impossible to remove data column : given data"
                             " object doesn't exist")

        log_item, legend_item = self.__data2logitems[data]
        for i, (pitem, litem) in enumerate(self.__columns):
            if pitem == log_item and litem == legend_item:
                self.__columns.pop(i)
                self.__column_widths.pop(i)
                del self.__data2logitems[data]
                self.__log_scene.removeItem(log_item)
                self.__log_scene.removeItem(legend_item)
                return

        # Columns not found
        assert False

    def clear_data_columns(self):
        # remove item from scenes
        for (item, legend) in self.__columns:
            self.__log_scene.removeItem(legend)
            self.__log_scene.removeItem(item)

        # remove from internal lists
        self.__columns = []
        self.__column_widths = []
        self.__data2logitems = {}

        self.__selected_column = -1
        self._place_items()
        self._update_button_visibility()

    def on_plot_tooltip(self, txt, station_name=None):
        if station_name is not None:
            self.__status_bar.showMessage(
                u"Station: {} ".format(station_name) + txt)
        else:
            self.__status_bar.showMessage(txt)

    def add_data_column(self, data, title, uom, station_name=None):
        plot_item = PlotItem(size=QSizeF(self.DEFAULT_COLUMN_WIDTH,
                                         self.__log_scene.height()),
                             render_type=POLYGON_RENDERER,
                             x_orientation=ORIENTATION_DOWNWARD,
                             y_orientation=ORIENTATION_LEFT_TO_RIGHT)

        plot_item.set_layer(data.get_layer())
        plot_item.tooltipRequested.connect(
            lambda txt: self.on_plot_tooltip(txt, station_name))

        legend_item = LegendItem(self.DEFAULT_COLUMN_WIDTH,
                                 title,
                                 unit_of_measure=uom)
        data.data_modified.connect(
            lambda data=data: self._update_data_column(data))

        self.__data2logitems[data] = (plot_item, legend_item)
        self._add_column(plot_item, legend_item)
        self._update_data_column(data)
        self._update_column_depths()

    def _update_data_column(self, data):

        plot_item, legend_item = self.__data2logitems[data]

        y_values = data.get_y_values()
        x_values = data.get_x_values()
        if y_values is None or x_values is None:
            plot_item.set_data_window(None)
            return

        plot_item.set_data(data.get_x_values(), data.get_y_values())

        #        r = QRectF(0, min_y, (max_x-min_x)/delta, max_y)
        #        plot_item.set_data_window(r)

        # legend
        min_str = "{:.1f}".format(min(data.get_y_values()))
        max_str = "{:.1f}".format(max(data.get_y_values()))
        legend_item.set_scale(min_str, max_str)

        self.__log_scene.update()

    def add_stratigraphy(self, layer, column_mapping, title):
        item = StratigraphyItem(self.DEFAULT_COLUMN_WIDTH,
                                self.__log_scene.height(),
                                style_file=os.path.join(
                                    self.__style_dir,
                                    "stratigraphy_style.xml"))
        legend_item = LegendItem(self.DEFAULT_COLUMN_WIDTH, title)

        item.set_layer(layer)
        item.tooltipRequested.connect(self.on_plot_tooltip)

        item.set_data(
            [[f[c] if c is not None else None for c in column_mapping]
             for f in layer.getFeatures()])

        self._add_column(item, legend_item)

    def add_imagery(self, image_filename, title, depth_from, depth_to):
        item = ImageryDataItem(self.DEFAULT_COLUMN_WIDTH,
                               self.__log_scene.height(), image_filename,
                               depth_from, depth_to)

        legend_item = LegendItem(self.DEFAULT_COLUMN_WIDTH, title)

        self._add_column(item, legend_item)

    def select_column_at(self, pos):
        x = pos.x()
        c = 0
        selected = -1
        for i, width in enumerate(self.__column_widths):
            if x >= c and x < c + width:
                selected = i
                break
            c += width
        self.select_column(selected)

    def select_column(self, idx):
        self.__selected_column = idx
        for i, p in enumerate(self.__columns):
            item, legend = p
            item.set_selected(idx == i)
            legend.set_selected(idx == i)
            item.update()
            legend.update()

        self._update_button_visibility()

    def selected_column(self):
        return self.__selected_column

    def _update_button_visibility(self):
        idx = self.__selected_column
        self.__action_move_column_left.setEnabled(idx != -1 and idx > 0)
        self.__action_move_column_right.setEnabled(
            idx != -1 and idx < len(self.__columns) - 1)
        self.__action_edit_style.setEnabled(idx != -1)
        self.__action_remove_column.setEnabled(idx != -1)

    def on_move_column_left(self):
        if self.__selected_column < 1:
            return

        sel = self.__selected_column
        self.__columns[
            sel -
            1], self.__columns[sel] = self.__columns[sel], self.__columns[sel -
                                                                          1]
        self.__column_widths[sel - 1], self.__column_widths[
            sel] = self.__column_widths[sel], self.__column_widths[sel - 1]
        self.__selected_column -= 1
        self._place_items()
        self._update_button_visibility()

    def on_move_column_right(self):
        if self.__selected_column == -1 or self.__selected_column >= len(
                self.__columns) - 1:
            return

        sel = self.__selected_column
        self.__columns[
            sel +
            1], self.__columns[sel] = self.__columns[sel], self.__columns[sel +
                                                                          1]
        self.__column_widths[sel + 1], self.__column_widths[
            sel] = self.__column_widths[sel], self.__column_widths[sel + 1]
        self.__selected_column += 1
        self._place_items()
        self._update_button_visibility()

    def on_remove_column(self):
        if self.__selected_column == -1:
            return

        sel = self.__selected_column

        # remove item from scenes
        item, legend = self.__columns[sel]
        self.__log_scene.removeItem(legend)
        self.__log_scene.removeItem(item)

        # remove from internal list
        del self.__columns[sel]
        del self.__column_widths[sel]
        self.__selected_column = -1
        self._place_items()
        self._update_button_visibility()

    def on_edit_style(self):
        if self.__selected_column == -1:
            return

        item = self.__columns[self.__selected_column][0]
        item.edit_style()

    def on_add_column(self):
        # to be overridden by subclasses
        pass
Exemple #7
0
 def addLayer(self, layer, headers, types, features):
     tab = QWidget()
     tab.layer = layer
     p1_vertical = QVBoxLayout(tab)
     p1_vertical.setContentsMargins(0,0,0,0)
     
     table = QTableWidget()
     table.itemSelectionChanged.connect(self.highlight_features)
     table.title = layer.name()
     table.crs = layer.crs()
     table.setColumnCount(len(headers))
     if len(features) > 0:
         table.setRowCount(len(features))
         nbrow = len(features)
         self.loadingWindow.show()
         self.loadingWindow.setLabelText(table.title)
         self.loadingWindow.activateWindow()
         self.loadingWindow.showNormal()
         
         # Table population
         m = 0
         for feature in features:
             n = 0
             for cell in feature.attributes():
                 item = QTableWidgetItem()
                 item.setData(Qt.DisplayRole, cell)
                 item.setFlags(item.flags() ^ Qt.ItemIsEditable)
                 item.feature = feature
                 table.setItem(m, n, item)
                 n += 1
             m += 1
             self.loadingWindow.setValue(int((float(m)/nbrow)*100))  
             QApplication.processEvents()
         
     else:
         table.setRowCount(0)  
                         
     table.setHorizontalHeaderLabels(headers)
     table.horizontalHeader().setSectionsMovable(True)
     
     table.types = types
     table.filter_op = []
     table.filters = []
     for i in range(0, len(headers)):
         table.filters.append('')
         table.filter_op.append(0)
     
     header = table.horizontalHeader()
     header.setContextMenuPolicy(Qt.CustomContextMenu)
     header.customContextMenuRequested.connect(partial(self.filterMenu, table))
         
     table.setSortingEnabled(True)
     
     p1_vertical.addWidget(table)
     
     # Status bar to display informations (ie: area)
     tab.sb = QStatusBar()
     p1_vertical.addWidget(tab.sb)
     
     title = table.title
     # We reduce the title's length to 20 characters
     if len(title)>20:
         title = title[:20]+'...'
     
     # We add the number of elements to the tab's title.
     title += ' ('+str(len(features))+')'
         
     self.tabWidget.addTab(tab, title) # Add the tab to the conatiner
     self.tabWidget.setTabToolTip(self.tabWidget.indexOf(tab), table.title) # Display a tooltip with the layer's full name