/*************************************************************************** * Copyright (C) gempa GmbH * * All rights reserved. * * Contact: gempa GmbH (seiscomp-dev@gempa.de) * * * * GNU Affero General Public License Usage * * This file may be used under the terms of the GNU Affero * * Public License version 3.0 as published by the Free Software Foundation * * and appearing in the file LICENSE included in the packaging of this * * file. Please review the following information to ensure the GNU Affero * * Public License version 3.0 requirements will be met: * * https://www.gnu.org/licenses/agpl-3.0.html. * * * * Other Usage * * Alternatively, this file may be used in accordance with the terms and * * conditions contained in a signed written agreement between you and * * gempa GmbH. * ***************************************************************************/ #ifndef SEISCOMP_GUI_RECORDVIEW_H #define SEISCOMP_GUI_RECORDVIEW_H #ifndef Q_MOC_RUN #include #include #include #endif #include #include #include namespace Seiscomp { namespace DataModel { SC_GUI_API bool operator<(const Seiscomp::DataModel::WaveformStreamID& left, const Seiscomp::DataModel::WaveformStreamID& right); } } namespace Seiscomp { class RecordSequence; namespace Gui { class TimeScale; class RecordStreamThread; class SC_GUI_API RecordView : public QWidget { Q_OBJECT public: enum SelectionMode { NoSelection = 0, SingleSelection, ExtendedSelection }; public: //! Default c'tor //! The mode defaults to ringbuffer with a buffer //! size of 30 minutes RecordView(QWidget *parent = 0, Qt::WindowFlags f = 0, TimeScale *timeScale = 0); //! Creates a RecordView using a time window RecordView(const Seiscomp::Core::TimeWindow&, QWidget *parent = 0, Qt::WindowFlags f = 0, TimeScale *timeScale = 0); //! Creates a RecordView using a timespan and //! a ringbuffer RecordView(const Seiscomp::Core::TimeSpan&, QWidget *parent = 0, Qt::WindowFlags f = 0, TimeScale *timeScale = 0); ~RecordView(); public: //! Sets the timewindow used for the stream data. //! Incoming records will only be inserted when they //! fit into the timewindow. void setTimeWindow(const Seiscomp::Core::TimeWindow& tw); //! Sets the buffersize used for the stream data. //! When setting the buffersize, incoming records will be //! appended to the end of the stream. Records that do not //! fit into the buffer will be removed from the front of //! the buffer: ringbuffer mode void setBufferSize(const Seiscomp::Core::TimeSpan& ts); //! Returns the number of record stream int rowCount() const; //! Returns the number of visible streams int visibleRowCount() const; //! Returns the stream ID used for a row DataModel::WaveformStreamID streamID(int row) const; //! Returns whether a row is enabled or not bool isEnabled(int row) const; //! Returns the item in row 'row' RecordViewItem* itemAt(int row) const; //! Returns the item for streamID RecordViewItem* item(const DataModel::WaveformStreamID& streamID) const; //! Adds a new item to the view. //! If there already has been added an item //! for streamID, nullptr is returned. RecordViewItem* addItem(const DataModel::WaveformStreamID&, const QString& stationCode, int slotCount = 0); //! Adds an existing item to the view bool addItem(RecordViewItem* item); //! Removes a particular row bool removeItem(int row); //! Removes a RecordViewItem bool removeItem(RecordViewItem*); //! Removes and returns the item from the given row in the recordview; //! otherwise returns nullptr. RecordViewItem* takeItem(int row); //! Removes the item from the view and returns true or false bool takeItem(RecordViewItem*); //! Cycles through all rows that row 'row' is the first //! row in the view void cycleToRow(int row); //! Removes all available rows void clear(); //! Clears all available records void clearRecords(); //! Sets the height of a row in pixels void setRowHeight(int height, bool allowStretch = false); //! Returns the current row height int rowHeight() const; //! Sets the default row height void setDefaultRowHeight(int height); //! Sets the number of column to use when a new row is created void setDefaultItemColumns(int numCols); //! Sets the spacing between each row in pixels void setRowSpacing(int spacing); //! Sets the width of the label for each row void setLabelWidth(int width); //! Returns the label width int labelWidth() const; //! Sets the spacing between the label and the recordwidget void setHorizontalSpacing(int); //! Returns the horizontal spacing int horizontalSpacing() const; //! En-/Disables showing frames around the labels and the //! recordwidgets void setFramesEnabled(bool); //! Sets frame margin of the labels and the recordwidgets void setFrameMargin(int margin); //! Sets the zoom factor used for zoom in/out slots void setZoomFactor(float factor); float zoomFactor() const; //! Returns the current zoom spot QPointF zoomSpot() const; void setMinimumRowHeight(int); void setMaximumRowHeight(int); void setRelativeRowHeight(int desiredNumberOfTraces); //! Returns the current alignment Seiscomp::Core::Time alignment() const; //! Returns the current item RecordViewItem* currentItem() const; QList selectedItems() const; double timeRangeMin() const; double timeRangeMax() const; double timeScale() const; //! Returns all streams belonging to a station QList stationStreams(const std::string& networkCode, const std::string& stationCode) const; //! Copies the view state from another recordview bool copyState(RecordView *from); //! Moves all items to another RecordView bool moveItemsTo(RecordView *to); //! Moves selected streams to another RecordView bool moveSelectionTo(RecordView *to); //! Sets the default actions for interactive keyboard //! navigation: //! - Left/Right: Moves the records left/right //! - '+'/'-': Zooms the records vertically //! - 'y'/'x': Zooms tehe records horizontally //! - 'f': Toggles filtering //! - 'r': Toggles showing filtered and raw records void setDefaultActions(); //! Sets the datasource to read records from. //! This method initializes the reader thread and //! holds it until start() is called bool setDataSource(const QString& streamURL); //! Connects to the data source virtual bool connectToDataSource(); //! Starts reading from the set data source virtual bool start(); //! Stops reading from the data source virtual void stop(); //! Returns the current recordstream thread RecordStreamThread* recordStreamThread() const; QWidget* infoWidget() const; TimeScale* timeWidget() const; /** * @brief Returns the time window covered by all available data * @return The data time window */ Core::TimeWindow coveredTimeRange() const; public slots: void setRecordUpdateInterval(int ms); //! Feeds a record into the RecordView //! A new row is appended if rec's stream id //! is fed for the first time bool feed(const Seiscomp::Record *rec); bool feed(const Seiscomp::RecordPtr rec); bool feed(Seiscomp::Record *rec); void scrollLeft(); void scrollLeftSlowly(); void scrollRight(); void scrollRightSlowly(); void scrollLineUp(); void scrollLineDown(); void scrollPageUp(); void scrollPageDown(); void scrollToTop(); void scrollToBottom(); void selectPreviousRow(); void selectNextRow(); void selectFirstRow(); void selectLastRow(); void enableFilter(bool); void enableFilter(int, bool); //! Whether to show the current selected recordstream or //! both recordstreams void showAllRecords(bool enable); //! Whether to show record borders void showRecordBorders(bool enable); //! Whether to draw the background using alternating colors //! The item background will be drawn using QPalette::Base and //! QPalette::AlternateBase void setAlternatingRowColors(bool enable); //! Enables/disables the scrollbar void showScrollBar(bool show); //! Whether to automatically insert new items for new records //! when using feed(...) void setAutoInsertItem(bool enable); void setAbsoluteTimeEnabled(bool enable); void setAutoScale(bool enable); void setAutoMaxScale(bool enable); bool isFilterEnabled() const; void setScale(double t, double a = 0.0f); void setTimeRange(double t1, double t2); void setSelection(double t1, double t2); void move(double offset); void setSelectionEnabled(bool); void setSelectionMode(SelectionMode mode); void clearSelection(); //! Sets the justification of the records regarding the //! alignment time. 0 (Left) ... 1 (Right) void setJustification(float); //! Aligns the RecordView regarding the justification in //! the current viewport on the set alignment time void align(); void horizontalZoom(float factor); void horizontalZoomIn() { horizontalZoom( _zoomFactor); } void horizontalZoomOut() { horizontalZoom(1.0f/_zoomFactor); } void verticalZoom(float factor); void verticalZoomIn() { verticalZoom(_zoomFactor); } void verticalZoomOut() { verticalZoom(1.0f/_zoomFactor); } void zoom(float factor); void zoomIn() { zoom(_zoomFactor); } void zoomOut() { zoom(1.0f/_zoomFactor); } void scaleAmplitudesUp(); void scaleAmplitudesDown(); void scaleVisibleAmplitudes(); void scaleAllRecords(); //! Sets the zoom spot. p is in global screen coordinates void setZoomSpotFromGlobal(const QPoint& p); //! Sets the relative zoom spot in logical coords void setZoomSpot(const QPointF& p); //! Sets the zoom rectangle in global coordinates. void setZoomRectFromGlobal(const QRect &rect); void setZoomRect(const QRectF &rect); //! Sort the items by text of the label using the text in //! row 'row' void sortByText(int row); //! Sort the items by text of the label using first text in //! row 'row1' and then text in row 'row2' void sortByText(int row1, int row2); //! Sort the items by the value set in column 'column' void sortByValue(int column); //! Sort the items by the value set in column1 and then //! by value in column2 void sortByValue(int column1, int column2); //! Sort the items by the value set in column1 then //! by value in column2 and finally by value in column3 void sortByValue(int column1, int column2, int column3); //! Sort the items by the value set in column1 then //! by value in column2 then by value in column3 and finally by value //! in column4 void sortByValue(int column1, int column2, int column3, int column4); //! Sort the items by text of a row and then by the value set in //! a column void sortByTextAndValue(int row, int column); //! Sort the items by the data set with RecordViewItem::setData void sortByData(); //! Finds a row by its text using regular expressions. //! The first occurence according the sorting is returned. //! If no item matches then -1 is returned. int findByText(int row, QRegExp ®exp, int startRow = 0) const; //! Sort the items by the time value of the markers with //! text markerText void sortByMarkerTime(const QString& markerText); void setAlignment(const Seiscomp::Core::Time& time); //! Aligns all rows on their marker with text set to //! text. void alignOnMarker(const QString& text); //! Sets the cursor text for all rows void setCursorText(const QString& text); //! Selects an item void setItemSelected(RecordViewItem* item, bool select); void deselectAllItems(); void setCurrentItem(RecordViewItem* item); void ensureVisible(int row); void showSlot(int slot); void showComponent(char componentCode); //! Enables zooming by drawing a zoomrect with //! the mouse void setZoomEnabled(bool); void setDefaultDisplay(); //! Sets the parameters used to filter the traces void setFilter(RecordWidget::Filter *filter); bool setFilterByName(const QString&); //! Returns the set filter instance RecordWidget::Filter *filter() const; void updateRecords(); void setRecordBorderDrawMode(RecordWidget::RecordBorderDrawMode mode); signals: void updatedRecords(); void fedRecord(RecordViewItem*, const Seiscomp::Record*); void updatedInterval(double da, double dt, double ofs); void toggledFilter(bool); void scaleChanged(double time, double amplitude); void timeRangeChanged(double tmin, double tmax); void selectionChanged(double smin, double smax); void alignmentChanged(const Seiscomp::Core::Time&); void amplScaleChanged(double); //! This signal will be emitted whenever a new item //! has been automatically added to the view. //! Connected classes can set the columns of the item //! depending on the first record used for creation //! of the item. void addedItem(const Seiscomp::Record*, Seiscomp::Gui::RecordViewItem*); //! This signal is emitted whenever an item will be enabled //! or disabled void changedItem(RecordViewItem*, bool enabled); //! This signal will be emitted when a time (absolut time) //! has been selected inside a RecordWidget void selectedTime(Seiscomp::Gui::RecordWidget*, Seiscomp::Core::Time); void progressStarted(); void progressChanged(int value); void progressFinished(); //! This signal will be emitted whenever the selection //! changes and when in SingleSelection mode void currentItemChanged(RecordViewItem* current, RecordViewItem* last); //! This signal is emitted whenever the selection changes. void selectionChanged(); void cursorTextChanged(const QString&); //! This signal is emitted when a filter string is dropped into the //! recordview and the filter has been set and enabled successfully void filterChanged(const QString&); private slots: void onItemClicked(RecordViewItem*, bool buttonDown = false, Qt::KeyboardModifiers = Qt::NoModifier); void selectedTime(Seiscomp::Core::Time); void sliderAction(int action); protected: //! This method can be reimplemented in derived //! classes to create a custom record widget virtual RecordWidget *createRecordWidget( const DataModel::WaveformStreamID &streamID ) const; //! This method can be reimplemented in derived //! classes to create a custom label virtual RecordLabel *createLabel(RecordViewItem*) const; bool event(QEvent* event); void showEvent(QShowEvent *event); void closeEvent(QCloseEvent *event); void resizeEvent(QResizeEvent *event); void dragEnterEvent(QDragEnterEvent *event); void dropEvent(QDropEvent *event); void closeThread(); private: void setupUi(); void colorItem(RecordViewItem* item, int row); void colorItem(RecordViewItem*); void scaleContent(); template void sortRows(std::list< std::pair >&); void layoutRows(); void applyBufferChange(); // bool buildFilter(const QString& text, std::vector* >* filterList); private: enum Mode { TIME_WINDOW, RING_BUFFER }; typedef QMap Items; typedef QVector Rows; typedef QSet SelectionList; SelectionMode _selectionMode; RecordStreamThread* _thread; RecordViewItem* _currentItem; TimeScale* _timeScaleWidget; QScrollArea* _scrollArea; QWidget* _timeScaleInfo; QLayout* _timeScaleAuxLayout; QAction* _filterAction; QAction* _absTimeAction; QTimer _recordUpdateTimer; SelectionList _selectedItems; Mode _mode; Seiscomp::Core::Time _timeStart; Seiscomp::Core::TimeSpan _timeSpan; Items _items; Rows _rows; Core::Time _alignment; QPointF _zoomSpot; int _rowHeight; int _minRowHeight; int _maxRowHeight; int _numberOfRows; int _defaultRowHeight; float _zoomFactor; double _tmin, _tmax; float _amin, _amax; // amplitude range double _timeScale; // pixels per second double _minTimeScale; double _amplScale; // amplitude units per pixel bool _filtering; // the filter state bool _alternatingColors; bool _showAllRecords; bool _showRecordBorders; bool _autoInsertItems; bool _autoScale; bool _autoMaxScale; bool _frames; int _frameMargin; int _horizontalSpacing; int _rowSpacing; int _labelWidth; int _labelColumns; RecordWidget::RecordBorderDrawMode _recordBorderDrawMode; RecordWidget::Filter *_filter; friend class RecordViewItem; }; } } #endif