@@ -61,7 +61,9 int main(int argc, char *argv[]) | |||||
61 | pluginDir.cd("../lib64/sciqlop"); |
|
61 | pluginDir.cd("../lib64/sciqlop"); | |
62 | } |
|
62 | } | |
63 | #else |
|
63 | #else | |
64 | __x86_64__ || __ppc64__ if (!pluginDir.cd("../lib/SciQlop")) { pluginDir.cd("../lib/sciqlop"); } |
|
64 | if (!pluginDir.cd("../lib/SciQlop")) { | |
|
65 | pluginDir.cd("../lib/sciqlop"); | |||
|
66 | } | |||
65 | #endif |
|
67 | #endif | |
66 | #endif |
|
68 | #endif | |
67 | qCDebug(LOG_PluginManager()) |
|
69 | qCDebug(LOG_PluginManager()) |
@@ -18,7 +18,6 public: | |||||
18 |
|
18 | |||
19 | /// Initializes the plugin |
|
19 | /// Initializes the plugin | |
20 | virtual void accept(IVisualizationWidgetVisitor *visitor) = 0; |
|
20 | virtual void accept(IVisualizationWidgetVisitor *visitor) = 0; | |
21 | virtual void close() = 0; |
|
|||
22 | virtual QString name() const = 0; |
|
21 | virtual QString name() const = 0; | |
23 | }; |
|
22 | }; | |
24 |
|
23 |
@@ -27,11 +27,12 public: | |||||
27 | virtual ~VisualizationGraphWidget(); |
|
27 | virtual ~VisualizationGraphWidget(); | |
28 |
|
28 | |||
29 | void addVariable(std::shared_ptr<Variable> variable); |
|
29 | void addVariable(std::shared_ptr<Variable> variable); | |
|
30 | /// Removes a variable from the graph | |||
|
31 | void removeVariable(std::shared_ptr<Variable> variable) noexcept; | |||
30 |
|
32 | |||
31 | // IVisualizationWidget interface |
|
33 | // IVisualizationWidget interface | |
32 | void accept(IVisualizationWidgetVisitor *visitor) override; |
|
34 | void accept(IVisualizationWidgetVisitor *visitor) override; | |
33 | bool canDrop(const Variable &variable) const override; |
|
35 | bool canDrop(const Variable &variable) const override; | |
34 | void close() override; |
|
|||
35 | QString name() const override; |
|
36 | QString name() const override; | |
36 |
|
37 | |||
37 | void updateDisplay(std::shared_ptr<Variable> variable); |
|
38 | void updateDisplay(std::shared_ptr<Variable> variable); | |
@@ -44,6 +45,8 private: | |||||
44 | spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl; |
|
45 | spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl; | |
45 |
|
46 | |||
46 | private slots: |
|
47 | private slots: | |
|
48 | /// Slot called when right clicking on the graph (displays a menu) | |||
|
49 | void onGraphMenuRequested(const QPoint &pos) noexcept; | |||
47 |
|
50 | |||
48 | void onRangeChanged(const QCPRange &t1, const QCPRange &t2); |
|
51 | void onRangeChanged(const QCPRange &t1, const QCPRange &t2); | |
49 |
|
52 |
@@ -35,13 +35,9 public: | |||||
35 | */ |
|
35 | */ | |
36 | VisualizationZoneWidget *createZone(std::shared_ptr<Variable> variable); |
|
36 | VisualizationZoneWidget *createZone(std::shared_ptr<Variable> variable); | |
37 |
|
37 | |||
38 | /// Remove a zone |
|
|||
39 | void removeZone(VisualizationZoneWidget *zone); |
|
|||
40 |
|
||||
41 | // IVisualizationWidget interface |
|
38 | // IVisualizationWidget interface | |
42 | void accept(IVisualizationWidgetVisitor *visitor) override; |
|
39 | void accept(IVisualizationWidgetVisitor *visitor) override; | |
43 | bool canDrop(const Variable &variable) const override; |
|
40 | bool canDrop(const Variable &variable) const override; | |
44 | void close() override; |
|
|||
45 | QString name() const override; |
|
41 | QString name() const override; | |
46 |
|
42 | |||
47 | private: |
|
43 | private: |
@@ -23,19 +23,9 public: | |||||
23 | explicit VisualizationWidget(QWidget *parent = 0); |
|
23 | explicit VisualizationWidget(QWidget *parent = 0); | |
24 | virtual ~VisualizationWidget(); |
|
24 | virtual ~VisualizationWidget(); | |
25 |
|
25 | |||
26 | /// Add a zone widget |
|
|||
27 | virtual void addTab(VisualizationTabWidget *tabWidget); |
|
|||
28 |
|
||||
29 | /// Create a tab using a Variable |
|
|||
30 | VisualizationTabWidget *createTab(); |
|
|||
31 |
|
||||
32 | /// Remove a tab |
|
|||
33 | void removeTab(VisualizationTabWidget *tab); |
|
|||
34 |
|
||||
35 | // IVisualizationWidget interface |
|
26 | // IVisualizationWidget interface | |
36 | void accept(IVisualizationWidgetVisitor *visitor) override; |
|
27 | void accept(IVisualizationWidgetVisitor *visitor) override; | |
37 | bool canDrop(const Variable &variable) const override; |
|
28 | bool canDrop(const Variable &variable) const override; | |
38 | void close() override; |
|
|||
39 | QString name() const override; |
|
29 | QString name() const override; | |
40 |
|
30 | |||
41 | public slots: |
|
31 | public slots: |
@@ -32,13 +32,9 public: | |||||
32 | */ |
|
32 | */ | |
33 | VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable); |
|
33 | VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable); | |
34 |
|
34 | |||
35 | /// Remove a graph |
|
|||
36 | void removeGraph(VisualizationGraphWidget *graph); |
|
|||
37 |
|
||||
38 | // IVisualizationWidget interface |
|
35 | // IVisualizationWidget interface | |
39 | void accept(IVisualizationWidgetVisitor *visitor) override; |
|
36 | void accept(IVisualizationWidgetVisitor *visitor) override; | |
40 | bool canDrop(const Variable &variable) const override; |
|
37 | bool canDrop(const Variable &variable) const override; | |
41 | void close() override; |
|
|||
42 | QString name() const override; |
|
38 | QString name() const override; | |
43 |
|
39 | |||
44 | private: |
|
40 | private: |
@@ -26,8 +26,7 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier; | |||||
26 | struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate { |
|
26 | struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate { | |
27 |
|
27 | |||
28 | // 1 variable -> n qcpplot |
|
28 | // 1 variable -> n qcpplot | |
29 |
std:: |
|
29 | std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap; | |
30 | m_VariableToPlotMultiMap; |
|
|||
31 | }; |
|
30 | }; | |
32 |
|
31 | |||
33 | VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent) |
|
32 | VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent) | |
@@ -37,9 +36,12 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget | |||||
37 | { |
|
36 | { | |
38 | ui->setupUi(this); |
|
37 | ui->setupUi(this); | |
39 |
|
38 | |||
40 | // qcpplot title |
|
39 | ui->graphNameLabel->setText(name); | |
41 | ui->widget->plotLayout()->insertRow(0); |
|
40 | ||
42 | ui->widget->plotLayout()->addElement(0, 0, new QCPTextElement{ui->widget, name}); |
|
41 | // 'Close' options : widget is deleted when closed | |
|
42 | setAttribute(Qt::WA_DeleteOnClose); | |||
|
43 | connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close); | |||
|
44 | ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton)); | |||
43 |
|
45 | |||
44 | // Set qcpplot properties : |
|
46 | // Set qcpplot properties : | |
45 | // - Drag (on x-axis) and zoom are enabled |
|
47 | // - Drag (on x-axis) and zoom are enabled | |
@@ -50,6 +52,11 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget | |||||
50 | connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>( |
|
52 | connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>( | |
51 | &QCPAxis::rangeChanged), |
|
53 | &QCPAxis::rangeChanged), | |
52 | this, &VisualizationGraphWidget::onRangeChanged); |
|
54 | this, &VisualizationGraphWidget::onRangeChanged); | |
|
55 | ||||
|
56 | // Activates menu when right clicking on the graph | |||
|
57 | ui->widget->setContextMenuPolicy(Qt::CustomContextMenu); | |||
|
58 | connect(ui->widget, &QCustomPlot::customContextMenuRequested, this, | |||
|
59 | &VisualizationGraphWidget::onGraphMenuRequested); | |||
53 | } |
|
60 | } | |
54 |
|
61 | |||
55 |
|
62 | |||
@@ -70,6 +77,21 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable) | |||||
70 | connect(variable.get(), SIGNAL(dataCacheUpdated()), this, SLOT(onDataCacheVariableUpdated())); |
|
77 | connect(variable.get(), SIGNAL(dataCacheUpdated()), this, SLOT(onDataCacheVariableUpdated())); | |
71 | } |
|
78 | } | |
72 |
|
79 | |||
|
80 | void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept | |||
|
81 | { | |||
|
82 | // Each component associated to the variable : | |||
|
83 | // - is removed from qcpplot (which deletes it) | |||
|
84 | // - is no longer referenced in the map | |||
|
85 | auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable); | |||
|
86 | for (auto it = componentsIt.first; it != componentsIt.second;) { | |||
|
87 | ui->widget->removePlottable(it->second); | |||
|
88 | it = impl->m_VariableToPlotMultiMap.erase(it); | |||
|
89 | } | |||
|
90 | ||||
|
91 | // Updates graph | |||
|
92 | ui->widget->replot(); | |||
|
93 | } | |||
|
94 | ||||
73 | void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor) |
|
95 | void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor) | |
74 | { |
|
96 | { | |
75 | if (visitor) { |
|
97 | if (visitor) { | |
@@ -88,19 +110,26 bool VisualizationGraphWidget::canDrop(const Variable &variable) const | |||||
88 | return true; |
|
110 | return true; | |
89 | } |
|
111 | } | |
90 |
|
112 | |||
91 |
|
|
113 | QString VisualizationGraphWidget::name() const | |
92 | { |
|
114 | { | |
93 | // The main view cannot be directly closed. |
|
115 | return ui->graphNameLabel->text(); | |
94 | return; |
|
|||
95 | } |
|
116 | } | |
96 |
|
117 | |||
97 | QString VisualizationGraphWidget::name() const |
|
118 | void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept | |
98 | { |
|
119 | { | |
99 | if (auto title = dynamic_cast<QCPTextElement *>(ui->widget->plotLayout()->elementAt(0))) { |
|
120 | QMenu graphMenu{}; | |
100 | return title->text(); |
|
121 | ||
|
122 | // Iterates on variables (unique keys) | |||
|
123 | for (auto it = impl->m_VariableToPlotMultiMap.cbegin(), | |||
|
124 | end = impl->m_VariableToPlotMultiMap.cend(); | |||
|
125 | it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) { | |||
|
126 | // 'Remove variable' action | |||
|
127 | graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()), | |||
|
128 | [ this, var = it->first ]() { removeVariable(var); }); | |||
101 | } |
|
129 | } | |
102 | else { |
|
130 | ||
103 | return QString{}; |
|
131 | if (!graphMenu.isEmpty()) { | |
|
132 | graphMenu.exec(mapToGlobal(pos)); | |||
104 | } |
|
133 | } | |
105 | } |
|
134 | } | |
106 |
|
135 |
@@ -36,6 +36,9 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *par | |||||
36 | impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)} |
|
36 | impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)} | |
37 | { |
|
37 | { | |
38 | ui->setupUi(this); |
|
38 | ui->setupUi(this); | |
|
39 | ||||
|
40 | // Widget is deleted when closed | |||
|
41 | setAttribute(Qt::WA_DeleteOnClose); | |||
39 | } |
|
42 | } | |
40 |
|
43 | |||
41 | VisualizationTabWidget::~VisualizationTabWidget() |
|
44 | VisualizationTabWidget::~VisualizationTabWidget() | |
@@ -59,10 +62,6 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Vari | |||||
59 | return zoneWidget; |
|
62 | return zoneWidget; | |
60 | } |
|
63 | } | |
61 |
|
64 | |||
62 | void VisualizationTabWidget::removeZone(VisualizationZoneWidget *zone) |
|
|||
63 | { |
|
|||
64 | } |
|
|||
65 |
|
||||
66 | void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor) |
|
65 | void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor) | |
67 | { |
|
66 | { | |
68 | if (visitor) { |
|
67 | if (visitor) { | |
@@ -93,12 +92,6 bool VisualizationTabWidget::canDrop(const Variable &variable) const | |||||
93 | return true; |
|
92 | return true; | |
94 | } |
|
93 | } | |
95 |
|
94 | |||
96 | void VisualizationTabWidget::close() |
|
|||
97 | { |
|
|||
98 | // The main view cannot be directly closed. |
|
|||
99 | return; |
|
|||
100 | } |
|
|||
101 |
|
||||
102 | QString VisualizationTabWidget::name() const |
|
95 | QString VisualizationTabWidget::name() const | |
103 | { |
|
96 | { | |
104 | return impl->m_Name; |
|
97 | return impl->m_Name; |
@@ -48,7 +48,13 VisualizationWidget::VisualizationWidget(QWidget *parent) | |||||
48 | enableMinimumCornerWidgetSize(true); |
|
48 | enableMinimumCornerWidgetSize(true); | |
49 | } |
|
49 | } | |
50 |
|
50 | |||
|
51 | // Removes widget from tab and closes it | |||
|
52 | auto widget = ui->tabWidget->widget(index); | |||
51 | ui->tabWidget->removeTab(index); |
|
53 | ui->tabWidget->removeTab(index); | |
|
54 | if (widget) { | |||
|
55 | widget->close(); | |||
|
56 | } | |||
|
57 | ||||
52 | qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index); |
|
58 | qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index); | |
53 |
|
59 | |||
54 | }; |
|
60 | }; | |
@@ -67,22 +73,6 VisualizationWidget::~VisualizationWidget() | |||||
67 | delete ui; |
|
73 | delete ui; | |
68 | } |
|
74 | } | |
69 |
|
75 | |||
70 | void VisualizationWidget::addTab(VisualizationTabWidget *tabWidget) |
|
|||
71 | { |
|
|||
72 | // NOTE: check is this method has to be deleted because of its dupplicated version visible as |
|
|||
73 | // lambda function (in the constructor) |
|
|||
74 | } |
|
|||
75 |
|
||||
76 | VisualizationTabWidget *VisualizationWidget::createTab() |
|
|||
77 | { |
|
|||
78 | } |
|
|||
79 |
|
||||
80 | void VisualizationWidget::removeTab(VisualizationTabWidget *tab) |
|
|||
81 | { |
|
|||
82 | // NOTE: check is this method has to be deleted because of its dupplicated version visible as |
|
|||
83 | // lambda function (in the constructor) |
|
|||
84 | } |
|
|||
85 |
|
||||
86 | void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor) |
|
76 | void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor) | |
87 | { |
|
77 | { | |
88 | if (visitor) { |
|
78 | if (visitor) { | |
@@ -111,12 +101,6 bool VisualizationWidget::canDrop(const Variable &variable) const | |||||
111 | return false; |
|
101 | return false; | |
112 | } |
|
102 | } | |
113 |
|
103 | |||
114 | void VisualizationWidget::close() |
|
|||
115 | { |
|
|||
116 | // The main view cannot be directly closed. |
|
|||
117 | return; |
|
|||
118 | } |
|
|||
119 |
|
||||
120 | QString VisualizationWidget::name() const |
|
104 | QString VisualizationWidget::name() const | |
121 | { |
|
105 | { | |
122 | return QStringLiteral("MainView"); |
|
106 | return QStringLiteral("MainView"); |
@@ -4,6 +4,8 | |||||
4 |
|
4 | |||
5 | #include "Visualization/VisualizationGraphWidget.h" |
|
5 | #include "Visualization/VisualizationGraphWidget.h" | |
6 |
|
6 | |||
|
7 | #include <SqpApplication.h> | |||
|
8 | ||||
7 | Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget") |
|
9 | Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget") | |
8 |
|
10 | |||
9 | namespace { |
|
11 | namespace { | |
@@ -30,6 +32,11 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *p | |||||
30 | ui->setupUi(this); |
|
32 | ui->setupUi(this); | |
31 |
|
33 | |||
32 | ui->zoneNameLabel->setText(name); |
|
34 | ui->zoneNameLabel->setText(name); | |
|
35 | ||||
|
36 | // 'Close' options : widget is deleted when closed | |||
|
37 | setAttribute(Qt::WA_DeleteOnClose); | |||
|
38 | connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close); | |||
|
39 | ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton)); | |||
33 | } |
|
40 | } | |
34 |
|
41 | |||
35 | VisualizationZoneWidget::~VisualizationZoneWidget() |
|
42 | VisualizationZoneWidget::~VisualizationZoneWidget() | |
@@ -53,10 +60,6 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<V | |||||
53 | return graphWidget; |
|
60 | return graphWidget; | |
54 | } |
|
61 | } | |
55 |
|
62 | |||
56 | void VisualizationZoneWidget::removeGraph(VisualizationGraphWidget *graph) |
|
|||
57 | { |
|
|||
58 | } |
|
|||
59 |
|
||||
60 | void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor) |
|
63 | void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor) | |
61 | { |
|
64 | { | |
62 | if (visitor) { |
|
65 | if (visitor) { | |
@@ -88,12 +91,6 bool VisualizationZoneWidget::canDrop(const Variable &variable) const | |||||
88 | return true; |
|
91 | return true; | |
89 | } |
|
92 | } | |
90 |
|
93 | |||
91 | void VisualizationZoneWidget::close() |
|
|||
92 | { |
|
|||
93 | // The main view cannot be directly closed. |
|
|||
94 | return; |
|
|||
95 | } |
|
|||
96 |
|
||||
97 | QString VisualizationZoneWidget::name() const |
|
94 | QString VisualizationZoneWidget::name() const | |
98 | { |
|
95 | { | |
99 | return ui->zoneNameLabel->text(); |
|
96 | return ui->zoneNameLabel->text(); |
@@ -15,7 +15,58 | |||||
15 | </property> |
|
15 | </property> | |
16 | <layout class="QVBoxLayout" name="verticalLayout"> |
|
16 | <layout class="QVBoxLayout" name="verticalLayout"> | |
17 | <item> |
|
17 | <item> | |
18 |
<widget class="Q |
|
18 | <widget class="QWidget" name="infobar" native="true"> | |
|
19 | <layout class="QHBoxLayout" name="horizontalLayout_2"> | |||
|
20 | <property name="leftMargin"> | |||
|
21 | <number>0</number> | |||
|
22 | </property> | |||
|
23 | <property name="topMargin"> | |||
|
24 | <number>0</number> | |||
|
25 | </property> | |||
|
26 | <property name="rightMargin"> | |||
|
27 | <number>0</number> | |||
|
28 | </property> | |||
|
29 | <property name="bottomMargin"> | |||
|
30 | <number>0</number> | |||
|
31 | </property> | |||
|
32 | <item> | |||
|
33 | <widget class="QLabel" name="graphNameLabel"> | |||
|
34 | <property name="styleSheet"> | |||
|
35 | <string notr="true">font: 75 9pt "MS Shell Dlg 2";</string> | |||
|
36 | </property> | |||
|
37 | <property name="text"> | |||
|
38 | <string>TextLabel</string> | |||
|
39 | </property> | |||
|
40 | <property name="textFormat"> | |||
|
41 | <enum>Qt::AutoText</enum> | |||
|
42 | </property> | |||
|
43 | <property name="alignment"> | |||
|
44 | <set>Qt::AlignCenter</set> | |||
|
45 | </property> | |||
|
46 | </widget> | |||
|
47 | </item> | |||
|
48 | <item> | |||
|
49 | <widget class="QToolButton" name="closeButton"> | |||
|
50 | <property name="styleSheet"> | |||
|
51 | <string notr="true">background-color: transparent;</string> | |||
|
52 | </property> | |||
|
53 | <property name="text"> | |||
|
54 | <string>Close</string> | |||
|
55 | </property> | |||
|
56 | </widget> | |||
|
57 | </item> | |||
|
58 | </layout> | |||
|
59 | </widget> | |||
|
60 | </item> | |||
|
61 | <item> | |||
|
62 | <widget class="QCustomPlot" name="widget" native="true"> | |||
|
63 | <property name="sizePolicy"> | |||
|
64 | <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> | |||
|
65 | <horstretch>0</horstretch> | |||
|
66 | <verstretch>0</verstretch> | |||
|
67 | </sizepolicy> | |||
|
68 | </property> | |||
|
69 | </widget> | |||
19 | </item> |
|
70 | </item> | |
20 | </layout> |
|
71 | </layout> | |
21 | </widget> |
|
72 | </widget> |
@@ -46,6 +46,16 | |||||
46 | </property> |
|
46 | </property> | |
47 | </widget> |
|
47 | </widget> | |
48 | </item> |
|
48 | </item> | |
|
49 | <item> | |||
|
50 | <widget class="QToolButton" name="closeButton"> | |||
|
51 | <property name="styleSheet"> | |||
|
52 | <string notr="true">background-color: transparent;</string> | |||
|
53 | </property> | |||
|
54 | <property name="text"> | |||
|
55 | <string>Close</string> | |||
|
56 | </property> | |||
|
57 | </widget> | |||
|
58 | </item> | |||
49 | </layout> |
|
59 | </layout> | |
50 | </widget> |
|
60 | </widget> | |
51 | </item> |
|
61 | </item> |
General Comments 0
You need to be logged in to leave comments.
Login now