]> git.sesse.net Git - kdenlive/commitdiff
several small fixes, introduce nice popup messages in statusbar taken from dolphin
authorJean-Baptiste Mardelle <jb@kdenlive.org>
Sat, 21 Jun 2008 23:56:26 +0000 (23:56 +0000)
committerJean-Baptiste Mardelle <jb@kdenlive.org>
Sat, 21 Jun 2008 23:56:26 +0000 (23:56 +0000)
svn path=/branches/KDE4/; revision=2262

src/CMakeLists.txt
src/customtrackview.cpp
src/customtrackview.h
src/definitions.h
src/kthumb.cpp
src/mainwindow.cpp
src/mainwindow.h
src/projectlistview.cpp
src/statusbarmessagelabel.cpp [new file with mode: 0644]
src/statusbarmessagelabel.h [new file with mode: 0644]

index 2fb8ff715c8498f4c3b13127ce3e6b41a8e7e4c4..cf74b7c814d80b9376ee118afb9b9d8011a35467 100644 (file)
@@ -113,6 +113,7 @@ set(kdenlive_SRCS
   markerdialog.cpp
   guide.cpp
   editguidecommand.cpp
+  statusbarmessagelabel.cpp
 )
 
 kde4_add_kcfg_files(kdenlive_SRCS GENERATE_MOC kdenlivesettings.kcfgc )
index 0c514f1560fe557478ee30074a76e1dd87d85bea..805be75ce43c406179782b696b107862d1f11abf 100644 (file)
@@ -604,7 +604,7 @@ void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track)
     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++) {
@@ -756,7 +756,6 @@ void CustomTrackView::addItem(DocClipBase *clip, QPoint pos) {
 
 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);
@@ -924,7 +923,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) {
     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())));
@@ -932,13 +931,12 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) {
         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());
@@ -953,7 +951,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) {
         }
 
         //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);
@@ -1145,6 +1143,7 @@ Transition *CustomTrackView::getTransitionItemAt(GenTime pos, int track) {
 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;
     }
@@ -1156,6 +1155,7 @@ void CustomTrackView::moveClip(const ItemInfo start, const ItemInfo end) {
 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;
     }
@@ -1185,6 +1185,7 @@ void CustomTrackView::resizeClip(const ItemInfo start, const ItemInfo end) {
     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;
     }
@@ -1322,6 +1323,7 @@ void CustomTrackView::slotSeekToNextSnap() {
 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;
     }
@@ -1348,6 +1350,7 @@ void CustomTrackView::slotAddClipMarker(int id, GenTime t, QString c) {
 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;
     }
@@ -1367,6 +1370,7 @@ void CustomTrackView::slotDeleteClipMarker() {
 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;
     }
index 020ea834e705e399e6726589f968ed87b503368b..a10e2d77ed84ff07333c1c87eeeaba6f5f138dd4 100644 (file)
@@ -171,6 +171,7 @@ signals:
     void transitionItemSelected(Transition*);
     void activateDocumentMonitor();
     void trackHeightChanged();
+    void displayMessage(const QString, MessageType);
 };
 
 #endif
index 69560e19f7a8c4246041c6a4ae603d8f5b236d3c..6fe7d5693e9bfcb796464789c800dcb321bd1548 100644 (file)
@@ -41,6 +41,13 @@ enum TRANSITIONTYPE {
     MIX_TRANSITION = 200
 };
 
+enum MessageType {
+    DefaultMessage,
+    OperationCompletedMessage,
+    InformationMessage,
+    ErrorMessage
+};
+
 enum TRACKTYPE { AUDIOTRACK = 0, VIDEOTRACK = 1 };
 
 struct TrackInfo {
index 88ab7b432d2bd460a3cbaf2671eb400fb33bcb40..50eb0abefc02f15b7b76dab2576a294301e11b0b 100644 (file)
@@ -375,7 +375,7 @@ void KThumb::getAudioThumbs(int channel, double frame, double frameLength, int a
 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());
     }
 }
 
index 5bfa08b0159f49a4fc126fccde53713b35d92107..c3399368a5f60902724c135ab75df781cfe6c3c2 100644 (file)
@@ -365,7 +365,6 @@ void MainWindow::setupActions() {
     statusProgressBar->setMaximum(100);
     statusProgressBar->setMaximumWidth(150);
     statusProgressBar->setVisible(false);
-    statusLabel = new QLabel(this);
 
     QWidget *w = new QWidget;
 
@@ -404,14 +403,14 @@ void MainWindow::setupActions() {
     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);
@@ -432,12 +431,17 @@ void MainWindow::setupActions() {
     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);
@@ -825,6 +829,7 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc) { //cha
             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)));
@@ -864,6 +869,9 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc) { //cha
     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)));
@@ -1035,10 +1043,10 @@ void MainWindow::slotFitZoom() {
 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);
     }
 }
index 0ce55128967251d78bc7a5425291fb071e94694a..1347b9f02c74678da205a90ecfd0b041cef1725a 100644 (file)
@@ -38,6 +38,7 @@
 #include "effectslist.h"
 #include "gentime.h"
 #include "definitions.h"
+#include "statusbarmessagelabel.h"
 
 class KdenliveDoc;
 class TrackView;
@@ -71,7 +72,6 @@ protected:
 private:
     KTabWidget* m_timelineArea;
     QProgressBar *statusProgressBar;
-    QLabel* statusLabel;
     void setupActions();
     KdenliveDoc *m_activeDocument;
     TrackView *m_activeTimeline;
@@ -126,6 +126,7 @@ private:
     QAction *m_buttonRazorTool;
     QActionGroup *m_toolGroup;
     QSlider *m_zoomSlider;
+    StatusBarMessageLabel *m_messageLabel;
 
     void readOptions();
     void saveOptions();
index fde83832c13a69e320d04bd7976fdfe5bea0827c..cb35caf4153d672f141dd5659453a8b29a00cf49 100644 (file)
@@ -209,7 +209,7 @@ void ProjectListView::mouseMoveEvent(QMouseEvent *event) {
         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;
diff --git a/src/statusbarmessagelabel.cpp b/src/statusbarmessagelabel.cpp
new file mode 100644 (file)
index 0000000..2e1c591
--- /dev/null
@@ -0,0 +1,303 @@
+/***************************************************************************
+ *   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"
diff --git a/src/statusbarmessagelabel.h b/src/statusbarmessagelabel.h
new file mode 100644 (file)
index 0000000..51312ca
--- /dev/null
@@ -0,0 +1,164 @@
+/***************************************************************************
+ *   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