You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

616 lines
17 KiB
C

/***************************************************************************
* 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 <seiscomp/gui/core/recordviewitem.h>
#include <seiscomp/gui/core/timescale.h>
#include <seiscomp/math/filter.h>
#endif
#include <QScrollArea>
#include <QTimer>
#include <QSet>
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<RecordViewItem*> selectedItems() const;
double timeRangeMin() const;
double timeRangeMax() const;
double timeScale() const;
//! Returns all streams belonging to a station
QList<RecordViewItem*> 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 &regexp, 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 <typename T>
void sortRows(std::list< std::pair<T, RecordViewItem*> >&);
void layoutRows();
void applyBufferChange();
// bool buildFilter(const QString& text, std::vector<Seiscomp::Math::Filtering::IIR::Filter<float>* >* filterList);
private:
enum Mode {
TIME_WINDOW,
RING_BUFFER
};
typedef QMap<DataModel::WaveformStreamID, RecordViewItem*> Items;
typedef QVector<RecordViewItem*> Rows;
typedef QSet<RecordViewItem*> 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