markerdialog.cpp
guide.cpp
editguidecommand.cpp
+ statusbarmessagelabel.cpp
)
kde4_add_kcfg_files(kdenlive_SRCS GENERATE_MOC kdenlivesettings.kcfgc )
if (itemList.isEmpty()) {
ClipItem *clip = getClipItemAt((int)pos.frames(m_document->fps()) + 1, track);
if (clip) itemList.append(clip);
- else kDebug() << "------ wrning, clip eff not found";
+ else emit displayMessage(i18n("Select a clip if you want to apply an effect"), ErrorMessage);
}
kDebug() << "// REQUESTING EFFECT ON CLIP: " << pos.frames(25) << ", TRK: " << track << "SELECTED ITEMS: " << itemList.count();
for (int i = 0; i < itemList.count(); i++) {
void CustomTrackView::dragMoveEvent(QDragMoveEvent * event) {
event->setDropAction(Qt::IgnoreAction);
- kDebug() << "+++++++++++++ DRAG MOVE, : " << mapToScene(event->pos()).x() << ", SCAL: " << m_scale;
if (m_dropItem) {
int track = (int)(mapToScene(event->pos()).y() / m_tracksHeight); //) * (m_scale * 50) + m_scale;
m_dropItem->moveTo((int)(mapToScene(event->pos()).x() / m_scale), m_scale, (int)((track - m_dropItem->track()) * m_tracksHeight), track);
if (m_operationMode == MOVE) {
setCursor(Qt::OpenHandCursor);
// move clip
- if (m_dragItem->type() == AVWIDGET && m_dragItemInfo.startPos != info.startPos) {
+ if (m_dragItem->type() == AVWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
MoveClipCommand *command = new MoveClipCommand(this, m_dragItemInfo, info, false);
m_commandStack->push(command);
m_document->renderer()->mltMoveClip((int)(m_tracksList.count() - m_dragItemInfo.track), (int)(m_tracksList.count() - m_dragItem->track()), (int) m_dragItemInfo.startPos.frames(m_document->fps()), (int)(m_dragItem->startPos().frames(m_document->fps())));
if (m_dragItem->type() == TRANSITIONWIDGET && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) {
MoveTransitionCommand *command = new MoveTransitionCommand(this, m_dragItemInfo, info, false);
m_commandStack->push(command);
- //kDebug()<<"/// MOVING TRS FROM: "<<(int)(m_tracksList.count() - m_startPos.y())<<", OFFSET: "<<(int) (m_dragItem->track() - m_startPos.y());
Transition *transition = (Transition *) m_dragItem;
transition->updateTransitionEndTrack(getPreviousVideoTrack(m_dragItem->track()));
m_document->renderer()->mltMoveTransition(transition->transitionTag(), (int)(m_tracksList.count() - m_dragItemInfo.track), (int)(m_tracksList.count() - m_dragItem->track()), transition->transitionEndTrack(), m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos);
}
- } else if (m_operationMode == RESIZESTART) {
+ } else if (m_operationMode == RESIZESTART && m_dragItem->startPos() != m_dragItemInfo.startPos) {
// resize start
if (m_dragItem->type() == AVWIDGET) {
m_document->renderer()->mltResizeClipStart(m_tracksList.count() - m_dragItem->track(), m_dragItem->endPos(), m_dragItem->startPos(), m_dragItemInfo.startPos, m_dragItem->cropStart(), m_dragItem->cropStart() + m_dragItem->endPos() - m_dragItem->startPos());
}
//m_document->renderer()->doRefresh();
- } else if (m_operationMode == RESIZEEND) {
+ } else if (m_operationMode == RESIZEEND && m_dragItem->endPos() != m_dragItemInfo.endPos) {
// resize end
if (m_dragItem->type() == AVWIDGET) {
ResizeClipCommand *command = new ResizeClipCommand(this, m_dragItemInfo, info, false);
void CustomTrackView::moveClip(const ItemInfo start, const ItemInfo end) {
ClipItem *item = getClipItemAt((int) start.startPos.frames(m_document->fps()) + 1, start.track);
if (!item) {
+ emit displayMessage(i18n("Cannot move clip at time: %1s on track %2", start.startPos.seconds(), start.track), ErrorMessage);
kDebug() << "---------------- ERROR, CANNOT find clip to move at.. ";// << startPos.x() * m_scale * FRAME_SIZE + 1 << ", " << startPos.y() * m_tracksHeight + m_tracksHeight / 2;
return;
}
void CustomTrackView::moveTransition(const ItemInfo start, const ItemInfo end) {
Transition *item = getTransitionItemAt((int)start.startPos.frames(m_document->fps()) + 1, start.track);
if (!item) {
+ emit displayMessage(i18n("Cannot move transition at time: %1s on track %2", start.startPos.seconds(), start.track), ErrorMessage);
kDebug() << "---------------- ERROR, CANNOT find transition to move... ";// << startPos.x() * m_scale * FRAME_SIZE + 1 << ", " << startPos.y() * m_tracksHeight + m_tracksHeight / 2;
return;
}
else offset = -1;
ClipItem *item = getClipItemAt((int)(start.startPos.frames(m_document->fps()) + offset), start.track);
if (!item) {
+ emit displayMessage(i18n("Cannot move clip at time: %1s on track %2", start.startPos.seconds(), start.track), ErrorMessage);
kDebug() << "---------------- ERROR, CANNOT find clip to resize at... "; // << startPos;
return;
}
void CustomTrackView::slotAddClipMarker() {
QList<QGraphicsItem *> itemList = scene()->selectedItems();
if (itemList.count() != 1) {
+ emit displayMessage(i18n("Cannot add marker if more than one clip is selected"), ErrorMessage);
kDebug() << "// CANNOT ADD MARKER IF MORE TAN ONE CLIP IS SELECTED....";
return;
}
void CustomTrackView::slotDeleteClipMarker() {
QList<QGraphicsItem *> itemList = scene()->selectedItems();
if (itemList.count() != 1) {
+ emit displayMessage(i18n("Cannot delete marker if more than one clip is selected"), ErrorMessage);
kDebug() << "// CANNOT DELETE MARKER IF MORE TAN ONE CLIP IS SELECTED....";
return;
}
void CustomTrackView::slotEditClipMarker() {
QList<QGraphicsItem *> itemList = scene()->selectedItems();
if (itemList.count() != 1) {
+ emit displayMessage(i18n("Cannot edit marker if more than one clip is selected"), ErrorMessage);
kDebug() << "// CANNOT DELETE MARKER IF MORE TAN ONE CLIP IS SELECTED....";
return;
}
void transitionItemSelected(Transition*);
void activateDocumentMonitor();
void trackHeightChanged();
+ void displayMessage(const QString, MessageType);
};
#endif
MIX_TRANSITION = 200
};
+enum MessageType {
+ DefaultMessage,
+ OperationCompletedMessage,
+ InformationMessage,
+ ErrorMessage
+};
+
enum TRACKTYPE { AUDIOTRACK = 0, VIDEOTRACK = 1 };
struct TrackInfo {
void KThumb::customEvent(QEvent * event) {
if (event->type() == 10005) {
ProgressEvent* p = (ProgressEvent*) event;
- m_clipManager->setThumbsProgress(m_url.path(), p->value());
+ m_clipManager->setThumbsProgress(i18n("Creating thumbnail for %1", m_url.fileName()), p->value());
}
}
statusProgressBar->setMaximum(100);
statusProgressBar->setMaximumWidth(150);
statusProgressBar->setVisible(false);
- statusLabel = new QLabel(this);
QWidget *w = new QWidget;
m_zoomSlider->setMaximumWidth(150);
m_zoomSlider->setMinimumWidth(100);
- const int contentHeight = QFontMetrics(w->font()).height() + 3;
+ const int contentHeight = QFontMetrics(w->font()).height() + 8;
QString style = "QSlider::groove:horizontal { border: 1px solid #999999;height: 8px }";
style.append("QSlider::handle:horizontal { background-color: white; border: 1px solid #999999;width: 8px;margin: -2px 0;border-radius: 3px; }");
m_zoomSlider->setStyleSheet(style);
//m_zoomSlider->setMaximumHeight(contentHeight);
//m_zoomSlider->height() + 5;
- statusBar()->setMinimumHeight(contentHeight + 5);
+ statusBar()->setMinimumHeight(contentHeight);
toolbar->addWidget(m_zoomSlider);
connect(m_buttonShowMarkers, SIGNAL(triggered()), this, SLOT(slotSwitchMarkersComments()));
layout->addWidget(toolbar);
- statusBar()->insertPermanentWidget(0, statusProgressBar, 1);
- statusBar()->insertPermanentWidget(1, statusLabel, 1);
+ m_messageLabel = new StatusBarMessageLabel(this);
+ m_messageLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ m_messageLabel->setMinimumTextHeight(contentHeight);
+
+ statusBar()->addWidget(m_messageLabel, 10);
+ statusBar()->addWidget(statusProgressBar, 0);
statusBar()->insertPermanentWidget(ID_TIMELINE_BUTTONS, w);
statusBar()->insertPermanentFixedItem("00:00:00:00", ID_TIMELINE_POS);
statusBar()->insertPermanentWidget(ID_TIMELINE_FORMAT, m_timecodeFormat);
statusBar()->setMaximumHeight(statusBar()->font().pointSize() * 4);
+ m_messageLabel->hide();
actionCollection()->addAction("select_tool", m_buttonSelectTool);
actionCollection()->addAction("razor_tool", m_buttonRazorTool);
disconnect(m_activeTimeline, SIGNAL(transitionItemSelected(Transition*)), transitionConfig, SLOT(slotTransitionItemSelected(Transition*)));
disconnect(trackView, SIGNAL(transitionItemSelected(Transition*)), this, SLOT(slotActivateTransitionView()));
disconnect(m_zoomSlider, SIGNAL(valueChanged(int)), m_activeTimeline, SLOT(slotChangeZoom(int)));
+ disconnect(trackView->projectView(), SIGNAL(displayMessage(const QString&, MessageType)), m_messageLabel, SLOT(setMessage(const QString&, MessageType)));
disconnect(m_activeDocument, SIGNAL(docModified(bool)), this, SLOT(slotUpdateDocumentState(bool)));
disconnect(effectStack, SIGNAL(updateClipEffect(ClipItem*, QDomElement, QDomElement)), m_activeTimeline->projectView(), SLOT(slotUpdateClipEffect(ClipItem*, QDomElement, QDomElement)));
disconnect(effectStack, SIGNAL(removeEffect(ClipItem*, QDomElement)), m_activeTimeline->projectView(), SLOT(slotDeleteEffect(ClipItem*, QDomElement)));
connect(m_zoomSlider, SIGNAL(valueChanged(int)), trackView, SLOT(slotChangeZoom(int)));
connect(trackView->projectView(), SIGNAL(zoomIn()), this, SLOT(slotZoomIn()));
connect(trackView->projectView(), SIGNAL(zoomOut()), this, SLOT(slotZoomOut()));
+ connect(trackView->projectView(), SIGNAL(displayMessage(const QString&, MessageType)), m_messageLabel, SLOT(setMessage(const QString&, MessageType)));
+
+
connect(effectStack, SIGNAL(updateClipEffect(ClipItem*, QDomElement, QDomElement)), trackView->projectView(), SLOT(slotUpdateClipEffect(ClipItem*, QDomElement, QDomElement)));
connect(effectStack, SIGNAL(removeEffect(ClipItem*, QDomElement)), trackView->projectView(), SLOT(slotDeleteEffect(ClipItem*, QDomElement)));
connect(effectStack, SIGNAL(changeEffectState(ClipItem*, QDomElement, bool)), trackView->projectView(), SLOT(slotChangeEffectState(ClipItem*, QDomElement, bool)));
void MainWindow::slotGotProgressInfo(const QString &message, int progress) {
statusProgressBar->setValue(progress);
if (progress >= 0) {
- if (!message.isEmpty()) statusLabel->setText(message);
+ if (!message.isEmpty()) m_messageLabel->setMessage(message, InformationMessage);//statusLabel->setText(message);
statusProgressBar->setVisible(true);
} else {
- statusLabel->setText(QString());
+ m_messageLabel->setMessage(QString(), DefaultMessage);
statusProgressBar->setVisible(false);
}
}
#include "effectslist.h"
#include "gentime.h"
#include "definitions.h"
+#include "statusbarmessagelabel.h"
class KdenliveDoc;
class TrackView;
private:
KTabWidget* m_timelineArea;
QProgressBar *statusProgressBar;
- QLabel* statusLabel;
void setupActions();
KdenliveDoc *m_activeDocument;
TrackView *m_activeTimeline;
QAction *m_buttonRazorTool;
QActionGroup *m_toolGroup;
QSlider *m_zoomSlider;
+ StatusBarMessageLabel *m_messageLabel;
void readOptions();
void saveOptions();
return;
{
- ProjectItem *clickItem = (ProjectItem *) itemAt(event->pos());
+ ProjectItem *clickItem = (ProjectItem *) itemAt(m_DragStartPosition); //event->pos());
if (clickItem) {
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * peter.penz@gmx.at *
+ * Code borrowed from Dolphin, adapted (2008) to Kdenlive by *
+ * Jean-Baptiste Mardelle, jb@kdenlive.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#include "statusbarmessagelabel.h"
+
+#include <kcolorscheme.h>
+#include <kiconloader.h>
+#include <kicon.h>
+#include <klocale.h>
+
+#include <QFontMetrics>
+#include <QPainter>
+#include <QKeyEvent>
+#include <QPushButton>
+#include <QPixmap>
+#include <QTimer>
+
+StatusBarMessageLabel::StatusBarMessageLabel(QWidget* parent) :
+ QWidget(parent),
+ m_type(DefaultMessage),
+ m_state(Default),
+ m_illumination(0),
+ m_minTextHeight(-1),
+ m_timer(0),
+ m_closeButton(0) {
+ setMinimumHeight(KIconLoader::SizeSmall);
+
+ QPalette palette;
+ palette.setColor(QPalette::Background, Qt::transparent);
+ setPalette(palette);
+
+ m_timer = new QTimer(this);
+ connect(m_timer, SIGNAL(timeout()),
+ this, SLOT(timerDone()));
+
+ m_closeButton = new QPushButton(i18nc("@action:button", "Close"), this);
+ m_closeButton->hide();
+ connect(m_closeButton, SIGNAL(clicked()),
+ this, SLOT(closeErrorMessage()));
+}
+
+StatusBarMessageLabel::~StatusBarMessageLabel() {
+}
+
+void StatusBarMessageLabel::setMessage(const QString& text,
+ MessageType type) {
+ if ((text == m_text) && (type == m_type)) {
+ return;
+ }
+
+ /*if (m_type == ErrorMessage) {
+ if (type == ErrorMessage) {
+ m_pendingMessages.insert(0, m_text);
+ } else if ((m_state != Default) || !m_pendingMessages.isEmpty()) {
+ // a non-error message should not be shown, as there
+ // are other pending error messages in the queue
+ return;
+ }
+ }*/
+
+ m_text = text;
+ m_type = type;
+
+ m_timer->stop();
+ m_illumination = 0;
+ m_state = Default;
+
+ const char* iconName = 0;
+ QPixmap pixmap;
+ switch (type) {
+ case OperationCompletedMessage:
+ iconName = "dialog-ok";
+ // "ok" icon should probably be "dialog-success", but we don't have that icon in KDE 4.0
+ m_closeButton->hide();
+ break;
+
+ case InformationMessage:
+ iconName = "dialog-information";
+ m_closeButton->hide();
+ break;
+
+ case ErrorMessage:
+ iconName = "dialog-warning";
+ m_timer->start(100);
+ m_state = Illuminate;
+
+ //updateCloseButtonPosition();
+ //m_closeButton->show();
+ break;
+
+ case DefaultMessage:
+ default:
+ m_closeButton->hide();
+ break;
+ }
+
+ m_pixmap = (iconName == 0) ? QPixmap() : SmallIcon(iconName);
+ QTimer::singleShot(GeometryTimeout, this, SLOT(assureVisibleText()));
+ show(); //update();
+}
+
+void StatusBarMessageLabel::setMinimumTextHeight(int min) {
+ if (min != m_minTextHeight) {
+ m_minTextHeight = min;
+ setMinimumHeight(min);
+ if (m_closeButton->height() > min) {
+ m_closeButton->setFixedHeight(min);
+ }
+ }
+}
+
+int StatusBarMessageLabel::widthGap() const {
+ QFontMetrics fontMetrics(font());
+ const int defaultGap = 10;
+ return fontMetrics.width(m_text) - availableTextWidth() + defaultGap;
+}
+
+void StatusBarMessageLabel::paintEvent(QPaintEvent* /* event */) {
+ QPainter painter(this);
+
+ // draw background
+ QColor backgroundColor = palette().window().color();
+ if (m_illumination > 0) {
+ // at this point, a: we are a second label being drawn over the already
+ // painted status area, so we can be translucent, and b: our palette's
+ // window color (bg only) seems to be wrong (always black)
+ KColorScheme scheme(palette().currentColorGroup(), KColorScheme::Window);
+ backgroundColor = scheme.background(KColorScheme::NegativeBackground).color();
+ backgroundColor.setAlpha(qMin(255, m_illumination*2));
+ }
+ painter.setBrush(backgroundColor);
+ painter.setPen(Qt::NoPen);
+ painter.drawRect(QRect(0, 0, width(), height()));
+
+ // draw pixmap
+ int x = BorderGap;
+ int y = (m_minTextHeight - m_pixmap.height()) / 2;
+
+ if (!m_pixmap.isNull()) {
+ painter.drawPixmap(x, y, m_pixmap);
+ x += m_pixmap.width() + BorderGap;
+ }
+
+ // draw text
+ painter.setPen(palette().windowText().color());
+ int flags = Qt::AlignVCenter;
+ if (height() > m_minTextHeight) {
+ flags = flags | Qt::TextWordWrap;
+ }
+ painter.drawText(QRect(x, 0, availableTextWidth(), height()), flags, m_text);
+ painter.end();
+}
+
+void StatusBarMessageLabel::resizeEvent(QResizeEvent* event) {
+ QWidget::resizeEvent(event);
+ //updateCloseButtonPosition();
+ QTimer::singleShot(GeometryTimeout, this, SLOT(assureVisibleText()));
+}
+
+void StatusBarMessageLabel::timerDone() {
+ switch (m_state) {
+ case Illuminate: {
+ // increase the illumination
+ const int illumination_max = 224;
+ if (m_illumination < illumination_max) {
+ m_illumination += 32;
+ if (m_illumination > illumination_max) {
+ m_illumination = illumination_max;
+ }
+ update();
+ } else {
+ m_state = Illuminated;
+ m_timer->start(5000);
+ }
+ break;
+ }
+
+ case Illuminated: {
+ // start desaturation
+ m_state = Desaturate;
+ m_timer->start(100);
+ break;
+ }
+
+ case Desaturate: {
+ // desaturate
+ if (m_illumination > 0) {
+ m_illumination -= 5;
+ update();
+ } else {
+ m_state = Default;
+ m_timer->stop();
+ reset();
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void StatusBarMessageLabel::assureVisibleText() {
+ if (m_text.isEmpty()) {
+ return;
+ }
+
+ int requiredHeight = m_minTextHeight;
+ if (m_type != DefaultMessage) {
+ // Calculate the required height of the widget thats
+ // needed for having a fully visible text. Note that for the default
+ // statusbar type (e. g. hover information) increasing the text height
+ // is not wanted, as this might rearrange the layout of items.
+
+ QFontMetrics fontMetrics(font());
+ const QRect bounds(fontMetrics.boundingRect(0, 0, availableTextWidth(), height(),
+ Qt::AlignVCenter | Qt::TextWordWrap, m_text));
+ requiredHeight = bounds.height();
+ if (requiredHeight < m_minTextHeight) {
+ requiredHeight = m_minTextHeight;
+ }
+ }
+
+ // Increase/decrease the current height of the widget to the
+ // required height. The increasing/decreasing is done in several
+ // steps to have an animation if the height is modified
+ // (see StatusBarMessageLabel::resizeEvent())
+ const int gap = m_minTextHeight / 2;
+ int minHeight = minimumHeight();
+ if (minHeight < requiredHeight) {
+ minHeight += gap;
+ if (minHeight > requiredHeight) {
+ minHeight = requiredHeight;
+ }
+ setMinimumHeight(minHeight);
+ updateGeometry();
+ } else if (minHeight > requiredHeight) {
+ minHeight -= gap;
+ if (minHeight < requiredHeight) {
+ minHeight = requiredHeight;
+ }
+ setMinimumHeight(minHeight);
+ updateGeometry();
+ }
+
+ //updateCloseButtonPosition();
+}
+
+int StatusBarMessageLabel::availableTextWidth() const {
+ const int buttonWidth = 0; /*(m_type == ErrorMessage) ?
+ m_closeButton->width() + BorderGap : 0;*/
+ return width() - m_pixmap.width() - (BorderGap * 4) - buttonWidth;
+}
+
+void StatusBarMessageLabel::updateCloseButtonPosition() {
+ const int x = width() - m_closeButton->width() - BorderGap;
+ const int y = (height() - m_closeButton->height()) / 2;
+ m_closeButton->move(x, y);
+}
+
+void StatusBarMessageLabel::closeErrorMessage() {
+ if (!showPendingMessage()) {
+ reset();
+ setMessage(m_defaultText, DefaultMessage);
+ }
+}
+
+bool StatusBarMessageLabel::showPendingMessage() {
+ if (!m_pendingMessages.isEmpty()) {
+ reset();
+ setMessage(m_pendingMessages.takeFirst(), ErrorMessage);
+ return true;
+ }
+ return false;
+}
+
+void StatusBarMessageLabel::reset() {
+ m_text.clear();
+ m_pixmap = QPixmap();
+ m_type = DefaultMessage;
+ update();
+}
+
+#include "statusbarmessagelabel.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2006 by Peter Penz *
+ * peter.penz@gmx.at *
+ * Code borrowed from Dolphin, adapted (2008) to Kdenlive by *
+ * Jean-Baptiste Mardelle, jb@kdenlive.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
+ ***************************************************************************/
+
+#ifndef STATUSBARMESSAGELABEL_H
+#define STATUSBARMESSAGELABEL_H
+
+
+#include <QtCore/QList>
+#include <QtGui/QPixmap>
+
+#include <QtGui/QWidget>
+#include <definitions.h>
+
+class QPaintEvent;
+class QResizeEvent;
+class QPushButton;
+class QTimer;
+
+/**
+ * @brief Represents a message text label as part of the status bar.
+ *
+ * Dependent from the given type automatically a corresponding icon
+ * is shown in front of the text. For message texts having the type
+ * DolphinStatusBar::Error a dynamic color blending is done to get the
+ * attention from the user.
+ */
+class StatusBarMessageLabel : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit StatusBarMessageLabel(QWidget* parent);
+ virtual ~StatusBarMessageLabel();
+
+ MessageType type() const;
+
+ const QString& text() const;
+
+ void setDefaultText(const QString& text);
+ const QString& defaultText() const;
+
+ // TODO: maybe a better approach is possible with the size hint
+ void setMinimumTextHeight(int min);
+ int minimumTextHeight() const;
+
+ /**
+ * Returns the gap of the width of the current set text to the
+ * width of the message label. A gap <= 0 means that the text
+ * fits into the available width.
+ */
+ int widthGap() const;
+
+protected:
+ /** @see QWidget::paintEvent() */
+ virtual void paintEvent(QPaintEvent* event);
+
+ /** @see QWidget::resizeEvent() */
+ virtual void resizeEvent(QResizeEvent* event);
+
+public slots:
+ void setMessage(const QString& text, MessageType type);
+
+private slots:
+ void timerDone();
+
+ /**
+ * Increases the height of the message label so that
+ * the given text fits into given area.
+ */
+ void assureVisibleText();
+
+ /**
+ * Returns the available width in pixels for the text.
+ */
+ int availableTextWidth() const;
+
+ /**
+ * Moves the close button to the upper right corner
+ * of the message label.
+ */
+ void updateCloseButtonPosition();
+
+ /**
+ * Closes the currently shown error message and replaces it
+ * by the next pending message.
+ */
+ void closeErrorMessage();
+
+private:
+ /**
+ * Shows the next pending error message. If no pending message
+ * was in the queue, false is returned.
+ */
+ bool showPendingMessage();
+
+ /**
+ * Resets the message label properties. This is useful when the
+ * result of invoking StatusBarMessageLabel::setMessage() should
+ * not rely on previous states.
+ */
+ void reset();
+
+private:
+ enum State {
+ Default,
+ Illuminate,
+ Illuminated,
+ Desaturate
+ };
+
+ enum { GeometryTimeout = 100 };
+ enum { BorderGap = 2 };
+
+ MessageType m_type;
+ State m_state;
+ int m_illumination;
+ int m_minTextHeight;
+ QTimer* m_timer;
+ QString m_text;
+ QString m_defaultText;
+ QList<QString> m_pendingMessages;
+ QPixmap m_pixmap;
+ QPushButton* m_closeButton;
+};
+
+inline MessageType StatusBarMessageLabel::type() const {
+ return m_type;
+}
+
+inline const QString& StatusBarMessageLabel::text() const {
+ return m_text;
+}
+
+inline void StatusBarMessageLabel::setDefaultText(const QString& text) {
+ m_defaultText = text;
+}
+
+inline const QString& StatusBarMessageLabel::defaultText() const {
+ return m_defaultText;
+}
+
+inline int StatusBarMessageLabel::minimumTextHeight() const {
+ return m_minTextHeight;
+}
+
+#endif