diff --git a/shell/progresswidget/overlaywidget.cpp b/shell/progresswidget/overlaywidget.cpp index 6961b1421..f3eb998ec 100644 --- a/shell/progresswidget/overlaywidget.cpp +++ b/shell/progresswidget/overlaywidget.cpp @@ -1,100 +1,99 @@ /** -*- c++ -*- * overlaywidget.h * * Copyright (c) 2004 David Faure * * 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; version 2 of the License * * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of this program with any edition of * the Qt library by Trolltech AS, Norway (or with modified versions * of Qt that use the same license as Qt), and distribute linked * combinations including the two. You must obey the GNU General * Public License in all respects for all of the code used other than * Qt. If you modify this file, you may extend this exception to * your version of the file, but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from * your version. */ #include "overlaywidget.h" #include #include #include +#include using namespace KDevelop; OverlayWidget::OverlayWidget( QWidget* alignWidget, QWidget* parent, const char* name ) - : QWidget( parent ), mAlignWidget( 0 ) + : QWidget( parent, Qt::Window | Qt::FramelessWindowHint ), mAlignWidget( 0 ) { auto hboxHBoxLayout = new QHBoxLayout(this); hboxHBoxLayout->setMargin(0); setObjectName(name); setAlignWidget( alignWidget ); + + setWindowFlags(Qt::WindowDoesNotAcceptFocus | windowFlags()); + + qApp->installEventFilter(this); } OverlayWidget::~OverlayWidget() { } void OverlayWidget::reposition() { if ( !mAlignWidget ) return; // p is in the alignWidget's coordinates QPoint p; // We are always above the alignWidget, right-aligned with it. p.setX( mAlignWidget->width() - width() ); p.setY( -height() ); - // Position in the toplevelwidget's coordinates - QPoint pTopLevel = mAlignWidget->mapTo( topLevelWidget(), p ); - // Position in the widget's parentWidget coordinates - QPoint pParent = parentWidget()->mapFrom( topLevelWidget(), pTopLevel ); + // Position in the global coordinates + QPoint global = mAlignWidget->mapToGlobal( p ); // Move 'this' to that position. - move( pParent ); + move( global ); } void OverlayWidget::setAlignWidget( QWidget * w ) { if (w == mAlignWidget) return; - if (mAlignWidget) - mAlignWidget->removeEventFilter(this); - mAlignWidget = w; - if (mAlignWidget) - mAlignWidget->installEventFilter(this); - reposition(); } bool OverlayWidget::eventFilter( QObject* o, QEvent* e) { - if ( o == mAlignWidget && - ( e->type() == QEvent::Move || e->type() == QEvent::Resize ) ) { + if (e->type() == QEvent::Move || e->type() == QEvent::Resize) { reposition(); + } else if (e->type() == QEvent::Close) { + close(); } + return QWidget::eventFilter(o,e); } void OverlayWidget::resizeEvent( QResizeEvent* ev ) { reposition(); QWidget::resizeEvent( ev ); } diff --git a/shell/progresswidget/progressdialog.cpp b/shell/progresswidget/progressdialog.cpp index a9d048a13..2cda08197 100644 --- a/shell/progresswidget/progressdialog.cpp +++ b/shell/progresswidget/progressdialog.cpp @@ -1,419 +1,411 @@ /** -*- c++ -*- * progressdialog.cpp * * Copyright (c) 2004 Till Adam , * David Faure * * 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; version 2 of the License * * 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. * * In addition, as a special exception, the copyright holders give * permission to link the code of this program with any edition of * the Qt library by Trolltech AS, Norway (or with modified versions * of Qt that use the same license as Qt), and distribute linked * combinations including the two. You must obey the GNU General * Public License in all respects for all of the code used other than * Qt. If you modify this file, you may extend this exception to * your version of the file, but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from * your version. */ #include "progressdialog.h" #include "progressmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KDevelop { static const int MAX_LABEL_WIDTH = 650; class TransactionItem; TransactionItemView::TransactionItemView( QWidget *parent, const char *name ) : QScrollArea( parent ) { setObjectName( name ); setFrameStyle( NoFrame ); mBigBox = new QWidget( this ); auto layout = new QVBoxLayout(mBigBox); layout->setMargin(0); setWidget( mBigBox ); setWidgetResizable( true ); - setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ); + setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Maximum ); } TransactionItem *TransactionItemView::addTransactionItem( ProgressItem *item, bool first ) { TransactionItem *ti = new TransactionItem( mBigBox, item, first ); mBigBox->layout()->addWidget( ti ); resize( mBigBox->width(), mBigBox->height() ); return ti; } void TransactionItemView::resizeEvent ( QResizeEvent *event ) { // Tell the layout in the parent (progressdialog) that our size changed updateGeometry(); QSize sz = parentWidget()->sizeHint(); int currentWidth = parentWidget()->width(); // Don't resize to sz.width() every time when it only reduces a little bit if ( currentWidth < sz.width() || currentWidth > sz.width() + 100 ) { currentWidth = sz.width(); } parentWidget()->resize( currentWidth, sz.height() ); QScrollArea::resizeEvent( event ); } QSize TransactionItemView::sizeHint() const { return minimumSizeHint(); } QSize TransactionItemView::minimumSizeHint() const { int f = 2 * frameWidth(); // Make room for a vertical scrollbar in all cases, to avoid a horizontal one int vsbExt = verticalScrollBar()->sizeHint().width(); - int minw = topLevelWidget()->width() / 3; - int maxh = topLevelWidget()->height() / 2; QSize sz( mBigBox->minimumSizeHint() ); - sz.setWidth( qMax( sz.width(), minw ) + f + vsbExt ); - sz.setHeight( qMin( sz.height(), maxh ) + f ); + sz.setWidth( sz.width() + f + vsbExt ); + sz.setHeight( sz.height() + f ); return sz; } -void TransactionItemView::slotLayoutFirstItem() +void TransactionItemView::slotItemCompleted(TransactionItem* item) { + // If completed item is the first, hide separator line for the one that will become first now + if (mBigBox->layout()->indexOf(item) == 0) { + auto *secondItem = mBigBox->layout()->itemAt(1); + if (secondItem) { + static_cast(secondItem->widget())->hideHLine(); + } + } + + mBigBox->layout()->removeWidget(item); + delete item; + //This slot is called whenever a TransactionItem is deleted, so this is a //good place to call updateGeometry(), so our parent takes the new size //into account and resizes. updateGeometry(); - - /* - The below relies on some details in Qt's behaviour regarding deleting - objects. This slot is called from the destroyed signal of an item just - going away. That item is at that point still in the list of chilren, but - since the vtable is already gone, it will have type QObject. The first - one with both the right name and the right class therefor is what will - be the first item very shortly. That's the one we want to remove the - hline for. - */ - TransactionItem *ti = mBigBox->findChild( "TransactionItem" ); - if ( ti ) { - ti->hideHLine(); - } } // ---------------------------------------------------------------------------- TransactionItem::TransactionItem( QWidget *parent, ProgressItem *item, bool first ) : QWidget( parent ), mCancelButton( 0 ), mItem( item ) { auto vbox = new QVBoxLayout(this); vbox->setSpacing( 2 ); vbox->setMargin( 2 ); setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); mFrame = new QFrame( this ); mFrame->setFrameShape( QFrame::HLine ); mFrame->setFrameShadow( QFrame::Raised ); mFrame->show(); vbox->setStretchFactor( mFrame, 3 ); vbox->addWidget( mFrame ); QWidget *h = new QWidget( this ); auto hboxLayout = new QHBoxLayout(h); hboxLayout->setMargin(0); hboxLayout->setSpacing( 5 ); vbox->addWidget( h ); mItemLabel = new QLabel( fontMetrics().elidedText( item->label(), Qt::ElideRight, MAX_LABEL_WIDTH ), h ); h->layout()->addWidget( mItemLabel ); h->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); mProgress = new QProgressBar( h ); hboxLayout->addWidget(mProgress); mProgress->setMaximum( 100 ); mProgress->setValue( item->progress() ); h->layout()->addWidget( mProgress ); if ( item->canBeCanceled() ) { mCancelButton = new QPushButton( QIcon::fromTheme( "dialog-cancel" ), QString(), h ); hboxLayout->addWidget(mCancelButton); mCancelButton->setToolTip( i18n( "Cancel this operation." ) ); connect ( mCancelButton, &QPushButton::clicked, this, &TransactionItem::slotItemCanceled); h->layout()->addWidget( mCancelButton ); } h = new QWidget( this ); hboxLayout = new QHBoxLayout(h); hboxLayout->setMargin(0); hboxLayout->setSpacing( 5 ); h->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) ); vbox->addWidget( h ); mItemStatus = new QLabel( h ); hboxLayout->addWidget(mItemStatus); mItemStatus->setTextFormat( Qt::RichText ); mItemStatus->setText( fontMetrics().elidedText( item->status(), Qt::ElideRight, MAX_LABEL_WIDTH ) ); h->layout()->addWidget( mItemStatus ); if ( first ) { hideHLine(); } } TransactionItem::~TransactionItem() { } void TransactionItem::hideHLine() { mFrame->hide(); } void TransactionItem::setProgress( int progress ) { mProgress->setValue( progress ); } void TransactionItem::setLabel( const QString &label ) { mItemLabel->setText( fontMetrics().elidedText( label, Qt::ElideRight, MAX_LABEL_WIDTH ) ); } void TransactionItem::setStatus( const QString &status ) { mItemStatus->setText( fontMetrics().elidedText( status, Qt::ElideRight, MAX_LABEL_WIDTH ) ); } void TransactionItem::setTotalSteps( int totalSteps ) { mProgress->setMaximum( totalSteps ); } void TransactionItem::slotItemCanceled() { if ( mItem ) { mItem->cancel(); } } void TransactionItem::addSubTransaction( ProgressItem *item ) { Q_UNUSED( item ); } // --------------------------------------------------------------------------- ProgressDialog::ProgressDialog( QWidget *alignWidget, QWidget *parent, const char *name ) : OverlayWidget( alignWidget, parent, name ), mWasLastShown( false ) { setAutoFillBackground( true ); mScrollView = new TransactionItemView( this, "ProgressScrollView" ); layout()->addWidget( mScrollView ); // No more close button for now, since there is no more autoshow /* QVBox* rightBox = new QVBox( this ); QToolButton* pbClose = new QToolButton( rightBox ); pbClose->setAutoRaise(true); pbClose->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); pbClose->setFixedSize( 16, 16 ); pbClose->setIcon( KIconLoader::global()->loadIconSet( "window-close", KIconLoader::Small, 14 ) ); pbClose->setToolTip( i18n( "Hide detailed progress window" ) ); connect(pbClose, SIGNAL(clicked()), this, SLOT(slotClose())); QWidget* spacer = new QWidget( rightBox ); // don't let the close button take up all the height rightBox->setStretchFactor( spacer, 100 ); */ /* * Get the singleton ProgressManager item which will inform us of * appearing and vanishing items. */ ProgressManager *pm = ProgressManager::instance(); connect ( pm, &ProgressManager::progressItemAdded, this, &ProgressDialog::slotTransactionAdded ); connect ( pm, &ProgressManager::progressItemCompleted, this, &ProgressDialog::slotTransactionCompleted ); connect ( pm, &ProgressManager::progressItemProgress, this, &ProgressDialog::slotTransactionProgress ); connect ( pm, &ProgressManager::progressItemStatus, this, &ProgressDialog::slotTransactionStatus ); connect ( pm, &ProgressManager::progressItemLabel, this, &ProgressDialog::slotTransactionLabel ); connect ( pm, &ProgressManager::progressItemUsesBusyIndicator, this, &ProgressDialog::slotTransactionUsesBusyIndicator ); connect ( pm, &ProgressManager::showProgressDialog, this, &ProgressDialog::slotShow ); } void ProgressDialog::closeEvent( QCloseEvent *e ) { e->accept(); hide(); } /* * Destructor */ ProgressDialog::~ProgressDialog() { // no need to delete child widgets. } void ProgressDialog::slotTransactionAdded( ProgressItem *item ) { if ( item->parent() ) { if ( mTransactionsToListviewItems.contains( item->parent() ) ) { TransactionItem * parent = mTransactionsToListviewItems[ item->parent() ]; parent->addSubTransaction( item ); } } else { const bool first = mTransactionsToListviewItems.empty(); TransactionItem *ti = mScrollView->addTransactionItem( item, first ); if ( ti ) { mTransactionsToListviewItems.insert( item, ti ); } if ( first && mWasLastShown ) { QTimer::singleShot( 1000, this, SLOT(slotShow()) ); } } } void ProgressDialog::slotTransactionCompleted( ProgressItem *item ) { if ( mTransactionsToListviewItems.contains( item ) ) { TransactionItem *ti = mTransactionsToListviewItems[ item ]; mTransactionsToListviewItems.remove( item ); ti->setItemComplete(); - QTimer::singleShot( 3000, ti, SLOT(deleteLater()) ); - // see the slot for comments as to why that works - connect ( ti, &TransactionItem::destroyed, - mScrollView, &TransactionItemView::slotLayoutFirstItem ); + QTimer::singleShot( 3000, mScrollView, [=] { mScrollView->slotItemCompleted(ti); } ); } // This was the last item, hide. if ( mTransactionsToListviewItems.empty() ) { QTimer::singleShot( 3000, this, SLOT(slotHide()) ); } } void ProgressDialog::slotTransactionCanceled( ProgressItem * ) { } void ProgressDialog::slotTransactionProgress( ProgressItem *item, unsigned int progress ) { if ( mTransactionsToListviewItems.contains( item ) ) { TransactionItem *ti = mTransactionsToListviewItems[ item ]; ti->setProgress( progress ); } } void ProgressDialog::slotTransactionStatus( ProgressItem *item, const QString &status ) { if ( mTransactionsToListviewItems.contains( item ) ) { TransactionItem *ti = mTransactionsToListviewItems[ item ]; ti->setStatus( status ); } } void ProgressDialog::slotTransactionLabel( ProgressItem *item, const QString &label ) { if ( mTransactionsToListviewItems.contains( item ) ) { TransactionItem *ti = mTransactionsToListviewItems[ item ]; ti->setLabel( label ); } } void ProgressDialog::slotTransactionUsesBusyIndicator( KDevelop::ProgressItem *item, bool value ) { if ( mTransactionsToListviewItems.contains( item ) ) { TransactionItem *ti = mTransactionsToListviewItems[ item ]; if ( value ) { ti->setTotalSteps( 0 ); } else { ti->setTotalSteps( 100 ); } } } void ProgressDialog::slotShow() { setVisible( true ); } void ProgressDialog::slotHide() { // check if a new item showed up since we started the timer. If not, hide if ( mTransactionsToListviewItems.isEmpty() ) { setVisible( false ); } } void ProgressDialog::slotClose() { mWasLastShown = false; setVisible( false ); } void ProgressDialog::setVisible( bool b ) { OverlayWidget::setVisible( b ); emit visibilityChanged( b ); } void ProgressDialog::slotToggleVisibility() { /* Since we are only hiding with a timeout, there is a short period of * time where the last item is still visible, but clicking on it in * the statusbarwidget should not display the dialog, because there * are no items to be shown anymore. Guard against that. */ mWasLastShown = isHidden(); if ( !isHidden() || !mTransactionsToListviewItems.isEmpty() ) { setVisible( isHidden() ); } } } diff --git a/shell/progresswidget/progressdialog.h b/shell/progresswidget/progressdialog.h index d4ced7424..340160f9f 100644 --- a/shell/progresswidget/progressdialog.h +++ b/shell/progresswidget/progressdialog.h @@ -1,139 +1,139 @@ /*************************************************************************** * Copyright (c) 2004 Till Adam * * based on imapprogressdialog.cpp ,which is * * Copyright (c) 2002-2003 Klar�vdalens Datakonsult AB * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library 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 Library 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 KDEVPLATFORM_PROGRESSDIALOG_H #define KDEVPLATFORM_PROGRESSDIALOG_H #include "overlaywidget.h" #include #include #include class QProgressBar; class QFrame; class QLabel; class QPushButton; namespace KDevelop { class ProgressItem; class TransactionItem; class SSLLabel; class TransactionItemView : public QScrollArea { Q_OBJECT public: explicit TransactionItemView( QWidget * parent = 0, const char * name = 0 ); virtual ~TransactionItemView() {} TransactionItem *addTransactionItem( ProgressItem *item, bool first ); QSize sizeHint() const override; QSize minimumSizeHint() const override; public Q_SLOTS: - void slotLayoutFirstItem(); + void slotItemCompleted(TransactionItem * item); protected: virtual void resizeEvent ( QResizeEvent *event ) override; private: QWidget *mBigBox; }; class TransactionItem : public QWidget { Q_OBJECT public: TransactionItem( QWidget *parent, ProgressItem *item, bool first ); ~TransactionItem(); void hideHLine(); void setProgress( int progress ); void setLabel( const QString & ); // the given text is interpreted as RichText, so you might need to // Qt::escape() it before passing void setStatus( const QString & ); void setTotalSteps( int totalSteps ); ProgressItem *item() const { return mItem; } void addSubTransaction( ProgressItem *item ); // The progressitem is deleted immediately, we take 5s to go out, // so better not use mItem during this time. void setItemComplete() { mItem = 0; } public Q_SLOTS: void slotItemCanceled(); protected: QProgressBar *mProgress; QPushButton *mCancelButton; QLabel *mItemLabel; QLabel *mItemStatus; QFrame *mFrame; ProgressItem *mItem; }; class ProgressDialog : public OverlayWidget { Q_OBJECT public: ProgressDialog( QWidget *alignWidget, QWidget *parent, const char *name = 0 ); ~ProgressDialog(); void setVisible( bool b ) override; public Q_SLOTS: void slotToggleVisibility(); protected Q_SLOTS: void slotTransactionAdded( KDevelop::ProgressItem *item ); void slotTransactionCompleted( KDevelop::ProgressItem *item ); void slotTransactionCanceled( KDevelop::ProgressItem *item ); void slotTransactionProgress( KDevelop::ProgressItem *item, unsigned int progress ); void slotTransactionStatus( KDevelop::ProgressItem *item, const QString & ); void slotTransactionLabel( KDevelop::ProgressItem *item, const QString & ); void slotTransactionUsesBusyIndicator( KDevelop::ProgressItem *, bool ); void slotClose(); void slotShow(); void slotHide(); Q_SIGNALS: void visibilityChanged( bool ); protected: virtual void closeEvent( QCloseEvent * ) override; TransactionItemView *mScrollView; QMap mTransactionsToListviewItems; bool mWasLastShown; }; } // namespace KDevelop #endif // __KDevelop_PROGRESSDIALOG_H__