akonadi
erroroverlay.cpp
00001 /* 00002 Copyright (c) 2008 Volker Krause <vkrause@kde.org> 00003 00004 This library is free software; you can redistribute it and/or modify it 00005 under the terms of the GNU Library General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or (at your 00007 option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, but WITHOUT 00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00011 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00012 License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to the 00016 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00017 02110-1301, USA. 00018 */ 00019 00020 #include "erroroverlay_p.h" 00021 #include "ui_erroroverlay.h" 00022 #include "selftestdialog_p.h" 00023 00024 #include <KDebug> 00025 #include <KIcon> 00026 #include <KLocale> 00027 00028 #include <QtCore/QEvent> 00029 #include <QtGui/QBoxLayout> 00030 #include <QtGui/QLabel> 00031 #include <QtGui/QPalette> 00032 00033 using namespace Akonadi; 00034 00035 //@cond PRIVATE 00036 00037 class ErrorOverlayStatic 00038 { 00039 public: 00040 QVector<QPair<QPointer<QWidget>, QPointer<QWidget> > > baseWidgets; 00041 }; 00042 00043 K_GLOBAL_STATIC( ErrorOverlayStatic, sInstanceOverlay ) 00044 00045 static bool isParentOf( QObject* o1, QObject* o2 ) 00046 { 00047 if ( !o1 || !o2 ) 00048 return false; 00049 if ( o1 == o2 ) 00050 return true; 00051 return isParentOf( o1, o2->parent() ); 00052 } 00053 00054 ErrorOverlay::ErrorOverlay( QWidget *baseWidget, QWidget * parent ) : 00055 QWidget( parent ? parent : baseWidget->window() ), 00056 mBaseWidget( baseWidget ), 00057 mBaseWidgetIsParent( false ), 00058 ui( new Ui::ErrorOverlay ) 00059 { 00060 Q_ASSERT( baseWidget ); 00061 00062 mBaseWidgetIsParent = isParentOf( mBaseWidget, this ); 00063 00064 // check existing overlays to detect cascading 00065 for ( QVector<QPair< QPointer<QWidget>, QPointer<QWidget> > >::Iterator it = sInstanceOverlay->baseWidgets.begin(); 00066 it != sInstanceOverlay->baseWidgets.end(); ) { 00067 if ( (*it).first == 0 || (*it).second == 0 ) { 00068 // garbage collection 00069 it = sInstanceOverlay->baseWidgets.erase( it ); 00070 continue; 00071 } 00072 if ( isParentOf( (*it).first, baseWidget ) ) { 00073 // parent already has an overlay, kill ourselves 00074 mBaseWidget = 0; 00075 hide(); 00076 deleteLater(); 00077 return; 00078 } 00079 if ( isParentOf( baseWidget, (*it).first ) ) { 00080 // child already has overlay, kill that one 00081 delete (*it).second; 00082 it = sInstanceOverlay->baseWidgets.erase( it ); 00083 continue; 00084 } 00085 ++it; 00086 } 00087 sInstanceOverlay->baseWidgets.append( qMakePair( mBaseWidget, QPointer<QWidget>( this ) ) ); 00088 00089 connect( baseWidget, SIGNAL( destroyed() ), SLOT( deleteLater() ) ); 00090 mPreviousState = mBaseWidget->isEnabled(); 00091 00092 ui->setupUi( this ); 00093 ui->notRunningIcon->setPixmap( KIcon( QLatin1String( "akonadi" ) ).pixmap( 64 ) ); 00094 ui->brokenIcon->setPixmap( KIcon( QString::fromLatin1( "dialog-error" ) ).pixmap( 64 ) ); 00095 ui->progressIcon->setPixmap( KIcon( QLatin1String( "akonadi" ) ).pixmap( 32 ) ); 00096 00097 connect( ui->startButton, SIGNAL( clicked() ), SLOT( startClicked() ) ); 00098 connect( ui->selfTestButton, SIGNAL( clicked() ), SLOT( selfTestClicked() ) ); 00099 00100 const ServerManager::State state = ServerManager::state(); 00101 mOverlayActive = state == ServerManager::Running; 00102 serverStateChanged( state ); 00103 connect( ServerManager::self(), SIGNAL( stateChanged( Akonadi::ServerManager::State ) ), 00104 SLOT( serverStateChanged( Akonadi::ServerManager::State ) ) ); 00105 00106 QPalette p = palette(); 00107 p.setColor( backgroundRole(), QColor( 0, 0, 0, 128 ) ); 00108 p.setColor( foregroundRole(), Qt::white ); 00109 setPalette( p ); 00110 setAutoFillBackground( true ); 00111 00112 mBaseWidget->installEventFilter( this ); 00113 00114 reposition(); 00115 } 00116 00117 ErrorOverlay::~ ErrorOverlay() 00118 { 00119 if ( mBaseWidget && !mBaseWidgetIsParent ) 00120 mBaseWidget->setEnabled( mPreviousState ); 00121 } 00122 00123 void ErrorOverlay::reposition() 00124 { 00125 if ( !mBaseWidget ) 00126 return; 00127 00128 // reparent to the current top level widget of the base widget if needed 00129 // needed eg. in dock widgets 00130 if ( parentWidget() != mBaseWidget->window() ) 00131 setParent( mBaseWidget->window() ); 00132 00133 // follow base widget visibility 00134 // needed eg. in tab widgets 00135 if ( !mBaseWidget->isVisible() ) { 00136 hide(); 00137 return; 00138 } 00139 if ( mOverlayActive ) 00140 show(); 00141 00142 // follow position changes 00143 const QPoint topLevelPos = mBaseWidget->mapTo( window(), QPoint( 0, 0 ) ); 00144 const QPoint parentPos = parentWidget()->mapFrom( window(), topLevelPos ); 00145 move( parentPos ); 00146 00147 // follow size changes 00148 // TODO: hide/scale icon if we don't have enough space 00149 resize( mBaseWidget->size() ); 00150 } 00151 00152 bool ErrorOverlay::eventFilter(QObject * object, QEvent * event) 00153 { 00154 if ( object == mBaseWidget && mOverlayActive && 00155 ( event->type() == QEvent::Move || event->type() == QEvent::Resize || 00156 event->type() == QEvent::Show || event->type() == QEvent::Hide || 00157 event->type() == QEvent::ParentChange ) ) { 00158 reposition(); 00159 } 00160 return QWidget::eventFilter( object, event ); 00161 } 00162 00163 void ErrorOverlay::startClicked() 00164 { 00165 ServerManager::start(); 00166 } 00167 00168 void ErrorOverlay::selfTestClicked() 00169 { 00170 SelfTestDialog dlg; 00171 dlg.exec(); 00172 } 00173 00174 void ErrorOverlay::serverStateChanged( ServerManager::State state ) 00175 { 00176 if ( !mBaseWidget ) 00177 return; 00178 00179 if ( state == ServerManager::Running && mOverlayActive ) { 00180 mOverlayActive = false; 00181 hide(); 00182 if ( !mBaseWidgetIsParent ) 00183 mBaseWidget->setEnabled( mPreviousState ); 00184 } else if ( !mOverlayActive ) { 00185 mOverlayActive = true; 00186 if ( mBaseWidget->isVisible() ) 00187 show(); 00188 00189 if ( !mBaseWidgetIsParent ) { 00190 mPreviousState = mBaseWidget->isEnabled(); 00191 mBaseWidget->setEnabled( false ); 00192 } 00193 00194 reposition(); 00195 } 00196 00197 if ( mOverlayActive ) { 00198 switch ( state ) { 00199 case ServerManager::NotRunning: 00200 ui->stackWidget->setCurrentWidget( ui->notRunningPage ); 00201 break; 00202 case ServerManager::Broken: 00203 ui->stackWidget->setCurrentWidget( ui->brokenPage ); 00204 break; 00205 case ServerManager::Starting: 00206 ui->progressPage->setToolTip( i18n( "Personal information management service is starting..." ) ); 00207 ui->progressDescription->setText( i18n( "Personal information management service is starting..." ) ); 00208 ui->stackWidget->setCurrentWidget( ui->progressPage ); 00209 break; 00210 case ServerManager::Stopping: 00211 ui->progressPage->setToolTip( i18n( "Personal information management service is shutting down..." ) ); 00212 ui->progressDescription->setText( i18n( "Personal information management service is shutting down..." ) ); 00213 ui->stackWidget->setCurrentWidget( ui->progressPage ); 00214 break; 00215 case ServerManager::Running: 00216 break; 00217 } 00218 } 00219 } 00220 00221 //@endcond 00222 00223 #include "erroroverlay_p.moc"