importantmessageswidget.cpp
1 //------------------------------------------------------------------------------
2 // importantmessageswidget.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2011 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "importantmessageswidget.h"
24 
25 #include "ui_importantmessageswidget.h"
26 #include "gui/icons.h"
27 #include <QDateTime>
28 #include <QLabel>
29 #include <QPointer>
30 #include <QVBoxLayout>
31 #include <functional>
32 
33 DClass<ImportantMessagesWidget> : public Ui::ImportantMessagesWidget
34 {
35 public:
36  class MessageLabel
37  {
38  public:
39  MessageLabel(QLabel *pLabel)
40  {
41  this->pLabel = pLabel;
42  this->timeCreated = QDateTime::currentDateTime();
43  }
44 
45  QLabel *pLabel;
46  QDateTime timeCreated;
47  };
48 
49  class Handler final : public ::ImportantMessagesWidget::Handler
50  {
51  public:
52  Handler(QPointer<::ImportantMessagesWidget> container, QPointer<QLabel> label,
53  std::function<void(QLabel *label)> remover)
54  : container(container), label(label), remover(remover)
55  {
56  }
57 
58  void remove() override
59  {
60  if (container != nullptr && label != nullptr)
61  {
62  remover(label.data());
63  }
64  }
65 
66  private:
67  QPointer<::ImportantMessagesWidget> container;
68  QPointer<QLabel> label;
69  std::function<void(QLabel *label)> remover;
70  };
71 
72  static const unsigned DEFAULT_MAX_MESSAGES = 0;
73  static const int MAX_MSG_KEEP_TIME_SEC = 10;
74 
75  QList<MessageLabel> labelWidgets;
76  int maxMessages;
77 };
78 
79 DPointered(ImportantMessagesWidget)
80 
82  : QWidget(pParent)
83 {
85  d->setupUi(this);
86  d->btnClear->setIcon(Icons::clear());
87 
88  this->hide();
89 }
90 
91 ImportantMessagesWidget::~ImportantMessagesWidget()
92 {
93 }
94 
95 QSharedPointer<ImportantMessagesWidget::Handler> ImportantMessagesWidget::addMessage(
96  const QString &message)
97 {
98  return addMessage(message, QDateTime());
99 }
100 
101 QSharedPointer<ImportantMessagesWidget::Handler> ImportantMessagesWidget::addMessage(
102  const QString &message, const QDateTime &dateTime)
103 {
104  QString strTimestamp = "";
105  if (dateTime.isValid())
106  strTimestamp = dateTime.toString("[hh:mm:ss]") + " ";
107 
108  QString formattedMessage = "<p>" + strTimestamp + message + "</p>";
109 
110  QLabel *pNewLabel = new QLabel(this);
111  pNewLabel->setText(formattedMessage);
112  pNewLabel->setTextInteractionFlags(pNewLabel->textInteractionFlags()
113  | Qt::TextSelectableByMouse);
114  pNewLabel->setCursor(Qt::IBeamCursor);
115  pNewLabel->setWordWrap(true);
116 
117  auto handler = QSharedPointer<PrivData<ImportantMessagesWidget>::Handler>::create(
118  QPointer<ImportantMessagesWidget>(this), QPointer<QLabel>(pNewLabel),
119  [this](QLabel *label){ remove(label); });
120 
121  d->labelWidgets << PrivData<ImportantMessagesWidget>::MessageLabel(pNewLabel);
122  d->messageLayout->addWidget(pNewLabel);
123 
124  // Remember that widget may be auto-hidden.
125  this->show();
126 
127  // Do not forget co clear oldest widgets if necessary.
128  dropOldWidgetsIfBeyondLimit();
129  return handler;
130 }
131 
132 QSharedPointer<ImportantMessagesWidget::Handler> ImportantMessagesWidget::addMessage(
133  const QString &message, unsigned timestamp)
134 {
135 #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
136  return addMessage(message, QDateTime::fromSecsSinceEpoch(timestamp));
137 #else
138  return addMessage(message, QDateTime::fromTime_t(timestamp));
139 #endif
140 }
141 
143 {
144  while (!d->labelWidgets.isEmpty())
145  {
146  removeOneOldest();
147  }
148 }
149 
150 void ImportantMessagesWidget::dropOldWidgetsIfBeyondLimit()
151 {
152  while (d->labelWidgets.size() > d->maxMessages)
153  {
154  PrivData<ImportantMessagesWidget>::MessageLabel &oldestLabel = d->labelWidgets.first();
155  int timeDifference = oldestLabel.timeCreated.secsTo(QDateTime::currentDateTime());
156 
158  removeOneOldest();
159  else
160  {
161  // Exit the loop as no message is old enough to be dropped.
162  // Messages are ordered in chronological order.
163  break;
164  }
165  }
166 }
167 
169 {
170  if (num >= d->labelWidgets.size())
171  clear();
172  else
173  {
174  for (; num > 0; --num)
175  removeOneOldest();
176  }
177 }
178 
180 {
181  if (!d->labelWidgets.isEmpty())
182  {
183  remove(d->labelWidgets.first().pLabel);
184  }
185 }
186 
187 void ImportantMessagesWidget::remove(QLabel *label)
188 {
189  if (label != nullptr)
190  {
191  for (auto it = d->labelWidgets.begin(); it != d->labelWidgets.end(); ++it)
192  {
193  if (it->pLabel == label)
194  {
195  delete it->pLabel;
196  d->labelWidgets.erase(it);
197  break;
198  }
199  }
200  }
201  if (d->labelWidgets.isEmpty())
202  {
203  // Auto-hide when there is nothing to show.
204  hide();
205  }
206 }
207 
209 {
210  return d->maxMessages;
211 }
212 
213 void ImportantMessagesWidget::setMaxMessages(unsigned num)
214 {
215  d->maxMessages = num;
216 }