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 ui->quitButton->setText( KStandardGuiItem::quit().text() ); 00097 ui->detailsQuitButton->setText( KStandardGuiItem::quit().text() ); 00098 00099 #ifndef KDEPIM_MOBILE_UI 00100 ui->quitButton->hide(); 00101 ui->detailsQuitButton->hide(); 00102 #endif 00103 00104 connect( ui->startButton, SIGNAL( clicked() ), SLOT( startClicked() ) ); 00105 connect( ui->quitButton, SIGNAL( clicked() ), SLOT( quitClicked() ) ); 00106 connect( ui->detailsQuitButton, SIGNAL( clicked() ), SLOT( quitClicked() ) ); 00107 connect( ui->selfTestButton, SIGNAL( clicked() ), SLOT( selfTestClicked() ) ); 00108 00109 const ServerManager::State state = ServerManager::state(); 00110 mOverlayActive = state == ServerManager::Running; 00111 serverStateChanged( state ); 00112 connect( ServerManager::self(), SIGNAL( stateChanged( Akonadi::ServerManager::State ) ), 00113 SLOT( serverStateChanged( Akonadi::ServerManager::State ) ) ); 00114 00115 QPalette p = palette(); 00116 p.setColor( backgroundRole(), QColor( 0, 0, 0, 128 ) ); 00117 p.setColor( foregroundRole(), Qt::white ); 00118 setPalette( p ); 00119 setAutoFillBackground( true ); 00120 00121 mBaseWidget->installEventFilter( this ); 00122 00123 reposition(); 00124 } 00125 00126 ErrorOverlay::~ ErrorOverlay() 00127 { 00128 if ( mBaseWidget && !mBaseWidgetIsParent ) 00129 mBaseWidget->setEnabled( mPreviousState ); 00130 } 00131 00132 void ErrorOverlay::reposition() 00133 { 00134 if ( !mBaseWidget ) 00135 return; 00136 00137 // reparent to the current top level widget of the base widget if needed 00138 // needed eg. in dock widgets 00139 if ( parentWidget() != mBaseWidget->window() ) 00140 setParent( mBaseWidget->window() ); 00141 00142 // follow base widget visibility 00143 // needed eg. in tab widgets 00144 if ( !mBaseWidget->isVisible() ) { 00145 hide(); 00146 return; 00147 } 00148 if ( mOverlayActive ) 00149 show(); 00150 00151 // follow position changes 00152 const QPoint topLevelPos = mBaseWidget->mapTo( window(), QPoint( 0, 0 ) ); 00153 const QPoint parentPos = parentWidget()->mapFrom( window(), topLevelPos ); 00154 move( parentPos ); 00155 00156 // follow size changes 00157 // TODO: hide/scale icon if we don't have enough space 00158 resize( mBaseWidget->size() ); 00159 } 00160 00161 bool ErrorOverlay::eventFilter(QObject * object, QEvent * event) 00162 { 00163 if ( object == mBaseWidget && mOverlayActive && 00164 ( event->type() == QEvent::Move || event->type() == QEvent::Resize || 00165 event->type() == QEvent::Show || event->type() == QEvent::Hide || 00166 event->type() == QEvent::ParentChange ) ) { 00167 reposition(); 00168 } 00169 return QWidget::eventFilter( object, event ); 00170 } 00171 00172 void ErrorOverlay::startClicked() 00173 { 00174 ServerManager::start(); 00175 } 00176 00177 void ErrorOverlay::quitClicked() 00178 { 00179 qApp->quit(); 00180 } 00181 00182 void ErrorOverlay::selfTestClicked() 00183 { 00184 SelfTestDialog dlg; 00185 dlg.exec(); 00186 } 00187 00188 void ErrorOverlay::serverStateChanged( ServerManager::State state ) 00189 { 00190 if ( !mBaseWidget ) 00191 return; 00192 00193 if ( state == ServerManager::Running && mOverlayActive ) { 00194 mOverlayActive = false; 00195 hide(); 00196 if ( !mBaseWidgetIsParent ) 00197 mBaseWidget->setEnabled( mPreviousState ); 00198 } else if ( !mOverlayActive ) { 00199 mOverlayActive = true; 00200 if ( mBaseWidget->isVisible() ) 00201 show(); 00202 00203 if ( !mBaseWidgetIsParent ) { 00204 mPreviousState = mBaseWidget->isEnabled(); 00205 mBaseWidget->setEnabled( false ); 00206 } 00207 00208 reposition(); 00209 } 00210 00211 if ( mOverlayActive ) { 00212 switch ( state ) { 00213 case ServerManager::NotRunning: 00214 ui->stackWidget->setCurrentWidget( ui->notRunningPage ); 00215 break; 00216 case ServerManager::Broken: 00217 ui->stackWidget->setCurrentWidget( ui->brokenPage ); 00218 break; 00219 case ServerManager::Starting: 00220 ui->progressPage->setToolTip( i18n( "Personal information management service is starting..." ) ); 00221 ui->progressDescription->setText( i18n( "Personal information management service is starting..." ) ); 00222 ui->stackWidget->setCurrentWidget( ui->progressPage ); 00223 break; 00224 case ServerManager::Stopping: 00225 ui->progressPage->setToolTip( i18n( "Personal information management service is shutting down..." ) ); 00226 ui->progressDescription->setText( i18n( "Personal information management service is shutting down..." ) ); 00227 ui->stackWidget->setCurrentWidget( ui->progressPage ); 00228 break; 00229 case ServerManager::Running: 00230 break; 00231 } 00232 } 00233 } 00234 00235 //@endcond 00236 00237 #include "erroroverlay_p.moc"