kjanuswidget.cpp

00001 /*  This file is part of the KDE Libraries
00002  *  Copyright (C) 1999-2000 Espen Sand (espensa@online.no)
00003  *  Copyright (C) 2003 Ravikiran Rajagopal (ravi@kde.org)
00004  *
00005  *  This library is free software; you can redistribute it and/or
00006  *  modify it under the terms of the GNU Library General Public
00007  *  License as published by the Free Software Foundation; either
00008  *  version 2 of the License, or (at your option) any later version.
00009  *
00010  *  This library is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  *  Library General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU Library General Public License
00016  *  along with this library; see the file COPYING.LIB.  If not, write to
00017  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  *  Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include <qbitmap.h>
00022 #include <qgrid.h>
00023 #include <qhbox.h>
00024 #include <qheader.h>
00025 #include <qlabel.h>
00026 #include <qlayout.h>
00027 #include <qobjectlist.h>
00028 #include <qpixmap.h>
00029 #include <qsplitter.h>
00030 #include <qtabwidget.h>
00031 #include <qvbox.h>
00032 #include <qwidgetstack.h>
00033 #include <qpainter.h>
00034 #include <qstyle.h>
00035 
00036 #include <kapplication.h>
00037 #include <kdialog.h> // Access to some static members
00038 #include <klocale.h>
00039 #include <kglobal.h>
00040 #include <kglobalsettings.h>
00041 #include <kseparator.h>
00042 #include <kdebug.h>
00043 #include "kjanuswidget.h"
00044 #include <klistview.h>
00045 #include "kpushbutton.h"
00046 #include "kguiitem.h"
00047 
00048 class KJanusWidget::IconListItem : public QListBoxItem
00049 {
00050   public:
00051     IconListItem( QListBox *listbox, const QPixmap &pixmap,
00052                   const QString &text );
00053     virtual int height( const QListBox *lb ) const;
00054     virtual int width( const QListBox *lb ) const;
00055     int expandMinimumWidth( int width );
00056     void highlight( bool erase );        
00057 
00058   protected:
00059     const QPixmap &defaultPixmap();
00060     void paint( QPainter *painter );
00061     
00062   private:
00063     void paintContents( QPainter *painter );  
00064   
00065     QPixmap mPixmap;
00066     int mMinimumWidth;
00067 };
00068 
00069 class KJanusWidget::KJanusWidgetPrivate
00070 {
00071 public:
00072   KJanusWidgetPrivate() : mNextPageIndex(0), mListFrame( 0 ) { }
00073 
00074   int mNextPageIndex; // The next page index.
00075 
00076   // Dictionary for multipage modes.
00077   QMap<int,QWidget*> mIntToPage;
00078   // Reverse dictionary. Used because showPage() may be performance critical.
00079   QMap<QWidget*,int> mPageToInt;
00080   // Dictionary of title string associated with page.
00081   QMap<int, QString> mIntToTitle;
00082 
00083   QWidget * mListFrame;
00084   QSplitter * mSplitter;
00085 };
00086 
00087 template class QPtrList<QListViewItem>;
00088 
00089 
00090 KJanusWidget::KJanusWidget( QWidget *parent, const char *name, int face )
00091   : QWidget( parent, name, 0 ),
00092     mValid(false), mPageList(0),
00093     mTitleList(0), mFace(face), mTitleLabel(0), mActivePageWidget(0),
00094     mShowIconsInTreeList(false), d(0)
00095 {
00096   QVBoxLayout *topLayout = new QVBoxLayout( this );
00097 
00098   if( mFace == TreeList || mFace == IconList )
00099   {
00100     d = new KJanusWidgetPrivate;
00101     d->mSplitter = 0;
00102 
00103     QFrame *page;
00104     if( mFace == TreeList )
00105     {
00106       d->mSplitter = new QSplitter( this );
00107       topLayout->addWidget( d->mSplitter, 10 );
00108       mTreeListResizeMode = QSplitter::KeepSize;
00109 
00110       d->mListFrame = new QWidget( d->mSplitter );
00111       QVBoxLayout *dummy = new QVBoxLayout( d->mListFrame, 0, KDialog::spacingHint() );
00112       dummy->setAutoAdd( true );
00113       mTreeList = new KListView( d->mListFrame );
00114       mTreeList->addColumn( QString::null );
00115       mTreeList->header()->hide();
00116       mTreeList->setRootIsDecorated(true);
00117       mTreeList->setSorting( -1 );
00118       connect( mTreeList, SIGNAL(selectionChanged()), SLOT(slotShowPage()) );
00119       connect( mTreeList, SIGNAL(clicked(QListViewItem *)), SLOT(slotItemClicked(QListViewItem *)));
00120 
00121       //
00122       // Page area. Title at top with a separator below and a pagestack using
00123       // all available space at bottom.
00124       //
00125       QFrame *p = new QFrame( d->mSplitter );
00126 
00127       QHBoxLayout *hbox = new QHBoxLayout( p, 0, 0 );
00128 
00129       page = new QFrame( p );
00130       hbox->addWidget( page, 10 );
00131     }
00132     else
00133     {
00134       QHBoxLayout *hbox = new QHBoxLayout( topLayout );
00135       d->mListFrame = new QWidget( this );
00136       hbox->addWidget( d->mListFrame );
00137 
00138       ( new QVBoxLayout( d->mListFrame, 0, 0 ) )->setAutoAdd( true );
00139       mIconList = new IconListBox( d->mListFrame );
00140 
00141       QFont listFont( mIconList->font() );
00142       listFont.setBold( true );
00143       mIconList->setFont( listFont );
00144 
00145       mIconList->verticalScrollBar()->installEventFilter( this );
00146       connect( mIconList, SIGNAL(selectionChanged()), SLOT(slotShowPage()));
00147       connect( mIconList, SIGNAL(onItem(QListBoxItem *)), SLOT(slotOnItem(QListBoxItem *)));
00148 
00149       hbox->addSpacing( KDialog::marginHint() );
00150       page = new QFrame( this );
00151       hbox->addWidget( page, 10 );
00152     }
00153 
00154     //
00155     // Rest of page area. Title at top with a separator below and a
00156     // pagestack using all available space at bottom.
00157     //
00158 
00159     QVBoxLayout *vbox = new QVBoxLayout( page, 0, KDialog::spacingHint() );
00160 
00161     mTitleLabel = new QLabel( i18n("Empty Page"), page, "KJanusWidgetTitleLabel" );
00162     vbox->addWidget( mTitleLabel, 0, QApplication::reverseLayout() ? AlignRight : AlignLeft );
00163 
00164     QFont titleFont( mTitleLabel->font() );
00165     titleFont.setBold( true );
00166     mTitleLabel->setFont( titleFont );
00167 
00168     mTitleSep = new KSeparator( page );
00169     mTitleSep->setFrameStyle( QFrame::HLine|QFrame::Plain );
00170     vbox->addWidget( mTitleSep );
00171 
00172     mPageStack = new QWidgetStack( page );
00173     connect(mPageStack, SIGNAL(aboutToShow(QWidget *)),
00174             SIGNAL(aboutToShowPage(QWidget *)));
00175     vbox->addWidget( mPageStack, 10 );
00176   }
00177   else if( mFace == Tabbed )
00178   {
00179     d = new KJanusWidgetPrivate;
00180 
00181     mTabControl = new QTabWidget( this );
00182     mTabControl->setMargin (KDialog::marginHint());
00183     connect(mTabControl, SIGNAL(currentChanged(QWidget *)),
00184             SIGNAL(aboutToShowPage(QWidget *)));
00185     topLayout->addWidget( mTabControl, 10 );
00186   }
00187   else if( mFace == Swallow )
00188   {
00189     mSwallowPage = new QWidget( this );
00190     topLayout->addWidget( mSwallowPage, 10 );
00191   }
00192   else
00193   {
00194     mFace = Plain;
00195     mPlainPage = new QFrame( this );
00196     topLayout->addWidget( mPlainPage, 10 );
00197   }
00198 
00199   if ( kapp )
00200     connect(kapp,SIGNAL(kdisplayFontChanged()),SLOT(slotFontChanged()));
00201   mValid = true;
00202 
00203   setSwallowedWidget(0); // Set default size if 'mFace' is Swallow.
00204 }
00205 
00206 
00207 KJanusWidget::~KJanusWidget()
00208 {
00209   delete d;
00210 }
00211 
00212 
00213 bool KJanusWidget::isValid() const
00214 {
00215   return mValid;
00216 }
00217 
00218 
00219 QFrame *KJanusWidget::plainPage()
00220 {
00221   return mPlainPage;
00222 }
00223 
00224 
00225 int KJanusWidget::face() const
00226 {
00227   return mFace;
00228 }
00229 
00230 QWidget *KJanusWidget::FindParent()
00231 {
00232   if( mFace == Tabbed ) {
00233     return mTabControl;
00234   }
00235   else {
00236     return this;
00237   }
00238 }
00239 
00240 QFrame *KJanusWidget::addPage( const QStringList &items, const QString &header,
00241                    const QPixmap &pixmap )
00242 {
00243   if( !mValid )
00244   {
00245     kdDebug() << "addPage: Invalid object" << endl;
00246     return 0;
00247   }
00248 
00249   QFrame *page = new QFrame( FindParent(), "page" );
00250   addPageWidget( page, items, header, pixmap );
00251 
00252   return page;
00253 }
00254 
00255 void KJanusWidget::pageGone( QObject *obj )
00256 {
00257   removePage( static_cast<QWidget*>( obj ) );
00258 }
00259 
00260 void KJanusWidget::slotReopen( QListViewItem * item )
00261 {
00262   if( item )
00263     item->setOpen( true );
00264 }
00265 
00266 QFrame *KJanusWidget::addPage( const QString &itemName, const QString &header,
00267           const QPixmap &pixmap )
00268 {
00269   QStringList items;
00270   items << itemName;
00271   return addPage(items, header, pixmap);
00272 }
00273 
00274 
00275 
00276 QVBox *KJanusWidget::addVBoxPage( const QStringList &items,
00277           const QString &header,
00278           const QPixmap &pixmap )
00279 {
00280   if( !mValid )
00281   {
00282     kdDebug() << "addPage: Invalid object" << endl;
00283     return 0;
00284   }
00285 
00286   QVBox *page = new QVBox(FindParent() , "page" );
00287   page->setSpacing( KDialog::spacingHint() );
00288   addPageWidget( page, items, header, pixmap );
00289 
00290   return page;
00291 }
00292 
00293 QVBox *KJanusWidget::addVBoxPage( const QString &itemName,
00294                   const QString &header,
00295                   const QPixmap &pixmap )
00296 {
00297   QStringList items;
00298   items << itemName;
00299   return addVBoxPage(items, header, pixmap);
00300 }
00301 
00302 QHBox *KJanusWidget::addHBoxPage( const QStringList &items,
00303                   const QString &header,
00304                   const QPixmap &pixmap )
00305 {
00306   if( !mValid ) {
00307     kdDebug() << "addPage: Invalid object" << endl;
00308     return 0;
00309   }
00310 
00311   QHBox *page = new QHBox(FindParent(), "page");
00312   page->setSpacing( KDialog::spacingHint() );
00313   addPageWidget( page, items, header, pixmap );
00314 
00315   return page;
00316 }
00317 
00318 QHBox *KJanusWidget::addHBoxPage( const QString &itemName,
00319                   const QString &header,
00320                   const QPixmap &pixmap )
00321 {
00322   QStringList items;
00323   items << itemName;
00324   return addHBoxPage(items, header, pixmap);
00325 }
00326 
00327 QGrid *KJanusWidget::addGridPage( int n, Orientation dir,
00328                   const QStringList &items,
00329                   const QString &header,
00330                   const QPixmap &pixmap )
00331 {
00332   if( !mValid )
00333   {
00334     kdDebug() << "addPage: Invalid object" << endl;
00335     return 0;
00336   }
00337 
00338   QGrid *page = new QGrid( n, dir, FindParent(), "page" );
00339   page->setSpacing( KDialog::spacingHint() );
00340   addPageWidget( page, items, header, pixmap );
00341 
00342   return page;
00343 }
00344 
00345 
00346 QGrid *KJanusWidget::addGridPage( int n, Orientation dir,
00347                   const QString &itemName,
00348                   const QString &header,
00349                   const QPixmap &pixmap )
00350 {
00351   QStringList items;
00352   items << itemName;
00353   return addGridPage(n, dir, items, header, pixmap);
00354 }
00355 
00356 void KJanusWidget::InsertTreeListItem(const QStringList &items, const QPixmap &pixmap, QFrame *page)
00357 {
00358   bool isTop = true;
00359   QListViewItem *curTop = 0, *child, *last, *newChild;
00360   unsigned int index = 1;
00361   QStringList curPath;
00362 
00363   for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it, index++ ) {
00364     QString name = (*it);
00365     bool isPath = ( index != items.count() );
00366 
00367     // Find the first child.
00368     if (isTop) {
00369       child = mTreeList->firstChild();
00370     }
00371     else {
00372       child = curTop->firstChild();
00373     }
00374 
00375     // Now search for a child with the current Name, and if it we doesn't
00376     // find it, then remember the location of the last child.
00377     for (last = 0; child && child->text(0) != name ; last = child, child = child->nextSibling());
00378 
00379     if (!last && !child) {
00380       // This node didn't have any children at all, lets just insert the
00381       // new child.
00382       if (isTop)
00383         newChild = new QListViewItem(mTreeList, name);
00384       else
00385         newChild = new QListViewItem(curTop, name);
00386 
00387     }
00388     else if (child) {
00389       // we found the given name in this child.
00390       if (!isPath) {
00391         kdDebug() << "The element inserted was already in the TreeList box!" << endl;
00392         return;
00393       }
00394       else {
00395         // Ok we found the folder
00396         newChild  = child;
00397       }
00398     }
00399     else {
00400       // the node had some children, but we didn't find the given name
00401       if (isTop)
00402         newChild = new QListViewItem(mTreeList, last, name);
00403       else
00404         newChild = new QListViewItem(curTop, last, name);
00405     }
00406 
00407     // Now make the element expandable if it is a path component, and make
00408     // ready for next loop
00409     if (isPath) {
00410       newChild->setExpandable(true);
00411       curTop = newChild;
00412       isTop = false;
00413       curPath << name;
00414 
00415       QString key = curPath.join("_/_");
00416       if (mFolderIconMap.contains(key)) {
00417         QPixmap p = mFolderIconMap[key];
00418         newChild->setPixmap(0,p);
00419       }
00420     }
00421     else {
00422       if (mShowIconsInTreeList) {
00423         newChild->setPixmap(0, pixmap);
00424       }
00425       mTreeListToPageStack.insert(newChild, page);
00426     }
00427   }
00428 }
00429 
00430 void KJanusWidget::addPageWidget( QFrame *page, const QStringList &items,
00431                   const QString &header,const QPixmap &pixmap )
00432 {
00433   connect(page, SIGNAL(destroyed(QObject*)), SLOT(pageGone(QObject*)));
00434 
00435   if( mFace == Tabbed )
00436   {
00437     mTabControl->addTab (page, items.last());
00438     d->mIntToPage[d->mNextPageIndex] = static_cast<QWidget*>(page);
00439     d->mPageToInt[static_cast<QWidget*>(page)] = d->mNextPageIndex;
00440     d->mNextPageIndex++;
00441   }
00442   else if( mFace == TreeList || mFace == IconList )
00443   {
00444     d->mIntToPage[d->mNextPageIndex] = static_cast<QWidget*>(page);
00445     d->mPageToInt[static_cast<QWidget*>(page)] = d->mNextPageIndex;
00446     mPageStack->addWidget( page, 0 );
00447 
00448     if (items.isEmpty()) {
00449       kdDebug() << "Invalid QStringList, with zero items" << endl;
00450       return;
00451     }
00452 
00453     if( mFace == TreeList )
00454     {
00455       InsertTreeListItem(items, pixmap, page);
00456     }
00457     else // mFace == IconList
00458     {
00459       QString itemName = items.last();
00460       IconListItem *item = new IconListItem( mIconList, pixmap, itemName );
00461       mIconListToPageStack.insert(item, page);
00462       mIconList->invalidateHeight();
00463       mIconList->invalidateWidth();
00464 
00465       if (mIconList->isVisible())
00466         mIconList->updateWidth();
00467     }
00468 
00469     //
00470     // Make sure the title label is sufficiently wide
00471     //
00472     QString lastName = items.last();
00473     const QString &title = (!header.isNull() ? header : lastName);
00474     QRect r = mTitleLabel->fontMetrics().boundingRect( title );
00475     if( mTitleLabel->minimumWidth() < r.width() )
00476     {
00477       mTitleLabel->setMinimumWidth( r.width() );
00478     }
00479     d->mIntToTitle[d->mNextPageIndex] = title;
00480     if( d->mIntToTitle.count() == 1 )
00481     {
00482       showPage(0);
00483     }
00484     d->mNextPageIndex++;
00485   }
00486   else
00487   {
00488     kdDebug() << "KJanusWidget::addPageWidget: can only add a page in Tabbed, TreeList or IconList modes" << endl;
00489   }
00490 
00491 }
00492 
00493 void KJanusWidget::setFolderIcon(const QStringList &path, const QPixmap &pixmap)
00494 {
00495   QString key = path.join("_/_");
00496   mFolderIconMap.insert(key,pixmap);
00497 }
00498 
00499 
00500 
00501 bool KJanusWidget::setSwallowedWidget( QWidget *widget )
00502 {
00503   if( mFace != Swallow || !mValid )
00504   {
00505     return false;
00506   }
00507 
00508   //
00509   // Remove current layout and make a new.
00510   //
00511   delete mSwallowPage->layout();
00512 
00513   QGridLayout *gbox = new QGridLayout( mSwallowPage, 1, 1, 0 );
00514 
00515   //
00516   // Hide old children
00517   //
00518   QObjectList *l = (QObjectList*)mSwallowPage->children(); // silence please
00519   for( uint i=0; i < l->count(); i++ )
00520   {
00521     QObject *o = l->at(i);
00522     if( o->isWidgetType() )
00523     {
00524       ((QWidget*)o)->hide();
00525     }
00526   }
00527 
00528   //
00529   // Add new child or make default size
00530   //
00531   if( !widget )
00532   {
00533     gbox->addRowSpacing(0,100);
00534     gbox->addColSpacing(0,100);
00535     mSwallowPage->setMinimumSize(100,100);
00536   }
00537   else
00538   {
00539     if( widget->parent() != mSwallowPage )
00540     {
00541       widget->reparent( mSwallowPage, 0, QPoint(0,0) );
00542     }
00543     gbox->addWidget(widget, 0, 0 );
00544     gbox->activate();
00545     mSwallowPage->setMinimumSize( widget->minimumSize() );
00546   }
00547 
00548   return true;
00549 }
00550 
00551 bool KJanusWidget::slotShowPage()
00552 {
00553   if( !mValid )
00554   {
00555     return false;
00556   }
00557 
00558   if( mFace == TreeList )
00559   {
00560     QListViewItem *node = mTreeList->selectedItem();
00561     if( !node ) { return false; }
00562 
00563     QWidget *stackItem = mTreeListToPageStack[node];
00564     // Make sure to call through the virtual function showPage(int)
00565     return showPage(d->mPageToInt[stackItem]);
00566   }
00567   else if( mFace == IconList )
00568   {
00569     QListBoxItem *node = mIconList->item( mIconList->currentItem() );
00570     if( !node ) { return false; }
00571     QWidget *stackItem = mIconListToPageStack[node];
00572     // Make sure to call through the virtual function showPage(int)
00573     return showPage(d->mPageToInt[stackItem]);
00574   }
00575 
00576   return false;
00577 }
00578 
00579 
00580 bool KJanusWidget::showPage( int index )
00581 {
00582   if( !d || !mValid )
00583   {
00584     return false;
00585   }
00586   else
00587   {
00588     return showPage(d->mIntToPage[index]);
00589   }
00590 }
00591 
00592 
00593 bool KJanusWidget::showPage( QWidget *w )
00594 {
00595   if( !w || !mValid )
00596   {
00597     return false;
00598   }
00599 
00600   if( mFace == TreeList || mFace == IconList )
00601   {
00602     mPageStack->raiseWidget( w );
00603     mActivePageWidget = w;
00604 
00605     int index = d->mPageToInt[w];
00606     mTitleLabel->setText( d->mIntToTitle[index] );
00607     if( mFace == TreeList )
00608     {
00609       QMap<QListViewItem *, QWidget *>::Iterator it;
00610       for (it = mTreeListToPageStack.begin(); it != mTreeListToPageStack.end(); ++it){
00611         QListViewItem *key = it.key();
00612         QWidget *val = it.data();
00613         if (val == w) {
00614           mTreeList->setSelected(key, true );
00615           break;
00616         }
00617       }
00618     }
00619     else
00620     {
00621       QMap<QListBoxItem *, QWidget *>::Iterator it;
00622       for (it = mIconListToPageStack.begin(); it != mIconListToPageStack.end(); ++it){
00623         QListBoxItem *key = it.key();
00624         QWidget *val = it.data();
00625         if (val == w) {
00626           mIconList->setSelected( key, true );
00627           break;
00628         }
00629       }
00630     }
00631   }
00632   else if( mFace == Tabbed )
00633   {
00634     mTabControl->showPage(w);
00635     mActivePageWidget = w;
00636   }
00637   else
00638   {
00639     return false;
00640   }
00641 
00642   return true;
00643 }
00644 
00645 
00646 int KJanusWidget::activePageIndex() const
00647 {
00648   if( mFace == TreeList) {
00649     QListViewItem *node = mTreeList->selectedItem();
00650     if( !node ) { return -1; }
00651     QWidget *stackItem = mTreeListToPageStack[node];
00652     return d->mPageToInt[stackItem];
00653   }
00654   else if (mFace == IconList) {
00655     QListBoxItem *node = mIconList->item( mIconList->currentItem() );
00656     if( !node ) { return false; }
00657     QWidget *stackItem = mIconListToPageStack[node];
00658     return d->mPageToInt[stackItem];
00659   }
00660   else if( mFace == Tabbed ) {
00661     QWidget *widget = mTabControl->currentPage();
00662     return ( !widget ? -1 : d->mPageToInt[widget] );
00663   }
00664   else {
00665     return -1;
00666   }
00667 }
00668 
00669 
00670 int KJanusWidget::pageIndex( QWidget *widget ) const
00671 {
00672   if( !widget )
00673   {
00674     return -1;
00675   }
00676   else if( mFace == TreeList || mFace == IconList )
00677   {
00678     return d->mPageToInt[widget];
00679   }
00680   else if( mFace == Tabbed )
00681   {
00682     //
00683     // The user gets the real page widget with addVBoxPage(), addHBoxPage()
00684     // and addGridPage() but not with addPage() which returns a child of
00685     // the toplevel page. addPage() returns a QFrame so I check for that.
00686     //
00687     if( widget->isA("QFrame") )
00688     {
00689       return d->mPageToInt[widget->parentWidget()];
00690     }
00691     else
00692     {
00693       return d->mPageToInt[widget];
00694     }
00695   }
00696   else
00697   {
00698     return -1;
00699   }
00700 }
00701 
00702 void KJanusWidget::slotFontChanged()
00703 {
00704   if( mTitleLabel )
00705   {
00706     mTitleLabel->setFont( KGlobalSettings::generalFont() );
00707     QFont titleFont( mTitleLabel->font() );
00708     titleFont.setBold( true );
00709     mTitleLabel->setFont( titleFont );
00710   }
00711 
00712   if( mFace == IconList )
00713   {
00714     QFont listFont( mIconList->font() );
00715     listFont.setBold( true );
00716     mIconList->setFont( listFont );
00717     mIconList->invalidateHeight();
00718     mIconList->invalidateWidth();
00719   }
00720 }
00721 
00722 // makes the treelist behave like the list of kcontrol
00723 void KJanusWidget::slotItemClicked(QListViewItem *it)
00724 {
00725   if(it && (it->childCount()>0))
00726     it->setOpen(!it->isOpen());
00727 }
00728 
00729 // hack because qt does not support Q_OBJECT in nested classes
00730 void KJanusWidget::slotOnItem(QListBoxItem *qitem)
00731 {
00732   mIconList->slotOnItem( qitem );
00733 }  
00734 
00735 void KJanusWidget::setFocus()
00736 {
00737   if( !mValid ) { return; }
00738   if( mFace == TreeList )
00739   {
00740     mTreeList->setFocus();
00741   }
00742   if( mFace == IconList )
00743   {
00744     mIconList->setFocus();
00745   }
00746   else if( mFace == Tabbed )
00747   {
00748     mTabControl->setFocus();
00749   }
00750   else if( mFace == Swallow )
00751   {
00752     mSwallowPage->setFocus();
00753   }
00754   else if( mFace == Plain )
00755   {
00756     mPlainPage->setFocus();
00757   }
00758 }
00759 
00760 
00761 QSize KJanusWidget::minimumSizeHint() const
00762 {
00763   if( mFace == TreeList || mFace == IconList )
00764   {
00765     QSize s1( KDialog::spacingHint(), KDialog::spacingHint()*2 );
00766     QSize s2(0,0);
00767     QSize s3(0,0);
00768     QSize s4( mPageStack->sizeHint() );
00769 
00770     if( mFace == TreeList )
00771     {
00772       s1.rwidth() += style().pixelMetric( QStyle::PM_SplitterWidth );
00773       s2 = mTreeList->minimumSize();
00774     }
00775     else
00776     {
00777       mIconList->updateMinimumHeight();
00778       mIconList->updateWidth();
00779       s2 = mIconList->minimumSize();
00780     }
00781 
00782     if( mTitleLabel->isVisible() )
00783     {
00784       s3 += mTitleLabel->sizeHint();
00785       s3.rheight() += mTitleSep->minimumSize().height();
00786     }
00787 
00788     //
00789     // Select the tallest item. It has only effect in IconList mode
00790     //
00791     int h1 = s1.rheight() + s3.rheight() + s4.height();
00792     int h2 = QMAX( h1, s2.rheight() );
00793 
00794     return QSize( s1.width()+s2.width()+QMAX(s3.width(),s4.width()), h2 );
00795   }
00796   else if( mFace == Tabbed )
00797   {
00798     return mTabControl->sizeHint();
00799   }
00800   else if( mFace == Swallow )
00801   {
00802     return mSwallowPage->minimumSize();
00803   }
00804   else if( mFace == Plain )
00805   {
00806     return mPlainPage->sizeHint();
00807   }
00808   else
00809   {
00810     return QSize( 100, 100 ); // Should never happen though.
00811   }
00812 
00813 }
00814 
00815 
00816 QSize KJanusWidget::sizeHint() const
00817 {
00818   return minimumSizeHint();
00819 }
00820 
00821 
00822 void KJanusWidget::setTreeListAutoResize( bool state )
00823 {
00824   if( mFace == TreeList )
00825   {
00826     mTreeListResizeMode = !state ?
00827       QSplitter::KeepSize : QSplitter::Stretch;
00828     if( d->mSplitter )
00829       d->mSplitter->setResizeMode( d->mListFrame, mTreeListResizeMode );
00830   }
00831 }
00832 
00833 
00834 void KJanusWidget::setIconListAllVisible( bool state )
00835 {
00836   if( mFace == IconList )
00837   {
00838     mIconList->setShowAll( state );
00839   }
00840 }
00841 
00842 void KJanusWidget::setShowIconsInTreeList( bool state )
00843 {
00844   mShowIconsInTreeList = state;
00845 }
00846 
00847 void KJanusWidget::setRootIsDecorated( bool state )
00848 {
00849   if( mFace == TreeList ) {
00850     mTreeList->setRootIsDecorated(state);
00851   }
00852 }
00853 
00854 void KJanusWidget::unfoldTreeList( bool persist )
00855 {
00856   if( mFace == TreeList )
00857   {
00858     if( persist )
00859       connect( mTreeList, SIGNAL( collapsed( QListViewItem * ) ), this, SLOT( slotReopen( QListViewItem * ) ) );
00860     else
00861       disconnect( mTreeList, SIGNAL( collapsed( QListViewItem * ) ), this, SLOT( slotReopen( QListViewItem * ) ) );
00862 
00863     for( QListViewItem * item = mTreeList->firstChild(); item; item = item->itemBelow() )
00864       item->setOpen( true );
00865   }
00866 }
00867 
00868 void KJanusWidget::addWidgetBelowList( QWidget * widget )
00869 {
00870   if( ( mFace == TreeList || mFace == IconList ) && d->mListFrame )
00871   {
00872     widget->reparent( d->mListFrame, QPoint() );
00873   }
00874 }
00875 
00876 void KJanusWidget::addButtonBelowList( const QString & text, QObject * recv, const char * slot )
00877 {
00878   if( ( mFace == TreeList || mFace == IconList ) && d->mListFrame )
00879   {
00880     QPushButton * button = new QPushButton( text, d->mListFrame, "KJanusWidget::buttonBelowList" );
00881     connect( button, SIGNAL( clicked() ), recv, slot );
00882   }
00883 }
00884 
00885 void KJanusWidget::addButtonBelowList( const KGuiItem & item, QObject * recv, const char * slot )
00886 {
00887   if( ( mFace == TreeList || mFace == IconList ) && d->mListFrame )
00888   {
00889     KPushButton * button = new KPushButton( item, d->mListFrame, "KJanusWidget::buttonBelowList" );
00890     connect( button, SIGNAL( clicked() ), recv, slot );
00891   }
00892 }
00893 
00894 void KJanusWidget::showEvent( QShowEvent * )
00895 {
00896   if( mFace == TreeList )
00897   {
00898     if( d->mSplitter )
00899       d->mSplitter->setResizeMode( d->mListFrame, mTreeListResizeMode );
00900   }
00901 }
00902 
00903 
00904 //
00905 // 2000-13-02 Espen Sand
00906 // It should be obvious that this eventfilter must only be
00907 // be installed on the vertical scrollbar of the mIconList.
00908 //
00909 bool KJanusWidget::eventFilter( QObject *o, QEvent *e )
00910 {
00911   if( e->type() == QEvent::Show )
00912   {
00913     IconListItem *item = (IconListItem*)mIconList->item(0);
00914     if( item )
00915     {
00916       int lw = item->width( mIconList );
00917       int sw = mIconList->verticalScrollBar()->sizeHint().width();
00918       mIconList->setFixedWidth( lw+sw+mIconList->frameWidth()*2 );
00919     }
00920   }
00921   else if( e->type() == QEvent::Hide )
00922   {
00923     IconListItem *item = (IconListItem*)mIconList->item(0);
00924     if( item )
00925     {
00926       int lw = item->width( mIconList );
00927       mIconList->setFixedWidth( lw+mIconList->frameWidth()*2 );
00928     }
00929   }
00930   return QWidget::eventFilter( o, e );
00931 }
00932 
00933 
00934 
00935 //
00936 // Code for the icon list box
00937 //
00938 
00939 
00940 KJanusWidget::IconListBox::IconListBox( QWidget *parent, const char *name,
00941                     WFlags f )
00942   :KListBox( parent, name, f ), mShowAll(false), mHeightValid(false),
00943    mWidthValid(false),
00944    mOldItem(0) 
00945 {
00946 }
00947 
00948 void KJanusWidget::IconListBox::updateMinimumHeight()
00949 {
00950   if( mShowAll && !mHeightValid )
00951   {
00952     int h = frameWidth()*2;
00953     for( QListBoxItem *i = item(0); i; i = i->next() )
00954     {
00955       h += i->height( this );
00956     }
00957     setMinimumHeight( h );
00958     mHeightValid = true;
00959   }
00960 }
00961 
00962 
00963 void KJanusWidget::IconListBox::updateWidth()
00964 {
00965   if( !mWidthValid )
00966   {
00967     int maxWidth = 10;
00968     for( QListBoxItem *i = item(0); i; i = i->next() )
00969     {
00970       int w = ((IconListItem *)i)->width(this);
00971       maxWidth = QMAX( w, maxWidth );
00972     }
00973 
00974     for( QListBoxItem *i = item(0); i; i = i->next() )
00975     {
00976       ((IconListItem *)i)->expandMinimumWidth( maxWidth );
00977     }
00978 
00979     if( verticalScrollBar()->isVisible() )
00980     {
00981       maxWidth += verticalScrollBar()->sizeHint().width();
00982     }
00983 
00984     setFixedWidth( maxWidth + frameWidth()*2 );
00985     mWidthValid = true;
00986   }
00987 }
00988 
00989 
00990 void KJanusWidget::IconListBox::invalidateHeight()
00991 {
00992   mHeightValid = false;
00993 }
00994 
00995 
00996 void KJanusWidget::IconListBox::invalidateWidth()
00997 {
00998   mWidthValid = false;
00999 }
01000 
01001 
01002 void KJanusWidget::IconListBox::setShowAll( bool showAll )
01003 {
01004   mShowAll = showAll;
01005   mHeightValid = false;
01006 }
01007 
01008 
01009 void KJanusWidget::IconListBox::leaveEvent( QEvent *ev )
01010 {
01011   KListBox::leaveEvent( ev ); 
01012 
01013   if ( mOldItem && !mOldItem->isSelected() )
01014   {
01015     ((KJanusWidget::IconListItem *) mOldItem)->highlight( true );
01016     mOldItem = 0;
01017   }
01018 } 
01019 
01020 // hack because qt does not support Q_OBJECT in nested classes
01021 void KJanusWidget::IconListBox::slotOnItem(QListBoxItem *qitem)
01022 {
01023   KListBox::slotOnItem( qitem );
01024 
01025   if ( qitem == mOldItem )
01026   {
01027     return;
01028   }
01029  
01030   if ( mOldItem && !mOldItem->isSelected() )
01031   {
01032     ((KJanusWidget::IconListItem *) mOldItem)->highlight( true );
01033   }
01034 
01035   KJanusWidget::IconListItem *item = dynamic_cast< KJanusWidget::IconListItem * >( qitem );
01036   if ( item && !item->isSelected() )
01037   {      
01038     item->highlight( false );
01039     mOldItem = item;
01040   }
01041   else
01042   {
01043     mOldItem = 0;
01044   }
01045 }  
01046 
01047 
01048 
01049 KJanusWidget::IconListItem::IconListItem( QListBox *listbox, const QPixmap &pixmap,
01050                                           const QString &text )
01051   : QListBoxItem( listbox )
01052 {
01053   mPixmap = pixmap;
01054   if( mPixmap.isNull() )
01055   {
01056     mPixmap = defaultPixmap();
01057   }
01058   setText( text );
01059   setCustomHighlighting( true );
01060   mMinimumWidth = 0;
01061 }
01062 
01063 
01064 int KJanusWidget::IconListItem::expandMinimumWidth( int width )
01065 {
01066   mMinimumWidth = QMAX( mMinimumWidth, width );
01067   return mMinimumWidth;
01068 }
01069 
01070 
01071 void KJanusWidget::IconListItem::highlight( bool erase )
01072 {   
01073    QRect r = listBox()->itemRect( this );
01074    r.addCoords( 1, 1, -1, -1 );  
01075    
01076    QPainter p( listBox()->viewport() );
01077    p.setClipRegion( r );
01078    
01079    const QColorGroup &cg = listBox()->colorGroup();
01080    if ( erase )
01081    {
01082       p.setPen( cg.base() );
01083       p.setBrush( cg.base() );
01084       p.drawRect( r );
01085    }
01086    else
01087    {
01088       p.setBrush( cg.highlight().light( 120 ) );
01089       p.drawRect( r );
01090 
01091       p.setPen( cg.highlight().dark( 140 ) );
01092       p.drawRect( r ); 
01093    }
01094       
01095    p.setPen( cg.foreground() );
01096    p.translate( r.x() - 1, r.y() - 1 );
01097    paintContents( &p );
01098 }
01099 
01100 
01101 const QPixmap &KJanusWidget::IconListItem::defaultPixmap()
01102 {
01103   static QPixmap *pix=0;
01104   if( !pix )
01105   {
01106     pix = new QPixmap( 32, 32 );
01107     QPainter p( pix );
01108     p.eraseRect( 0, 0, pix->width(), pix->height() );
01109     p.setPen( Qt::red );
01110     p.drawRect ( 0, 0, pix->width(), pix->height() );
01111     p.end();
01112 
01113     QBitmap mask( pix->width(), pix->height(), true );
01114     mask.fill( Qt::black );
01115     p.begin( &mask );
01116     p.setPen( Qt::white );
01117     p.drawRect ( 0, 0, pix->width(), pix->height() );
01118     p.end();
01119 
01120     pix->setMask( mask );
01121   }
01122   return *pix;
01123 }
01124 
01125 
01126 void KJanusWidget::IconListItem::paint( QPainter *painter )
01127 {
01128   QRect itemPaintRegion( listBox()->itemRect( this ) );
01129   QRect r( 1, 1, itemPaintRegion.width() - 2, itemPaintRegion.height() - 2);
01130 
01131   if ( isSelected() )
01132   {
01133     painter->eraseRect( r );
01134 
01135     painter->save();
01136     painter->setPen( listBox()->colorGroup().highlight().dark( 160 ) );
01137     painter->drawRect( r );
01138     painter->restore();
01139   }
01140 
01141   paintContents( painter );
01142 }
01143 
01144 
01145 void KJanusWidget::IconListItem::paintContents( QPainter *painter )
01146 {
01147   QFontMetrics fm = painter->fontMetrics();
01148   int ht = fm.boundingRect( 0, 0, 0, 0, Qt::AlignCenter, text() ).height();
01149   int wp = mPixmap.width();
01150   int hp = mPixmap.height();
01151   painter->drawPixmap( (mMinimumWidth - wp) / 2, 5, mPixmap );
01152 
01153   if( !text().isEmpty() )
01154   {
01155     painter->drawText( 1, hp + 7, mMinimumWidth - 2, ht, Qt::AlignCenter, text() );
01156   }
01157 }
01158 
01159 int KJanusWidget::IconListItem::height( const QListBox *lb ) const
01160 {
01161   if( text().isEmpty() )
01162   {
01163     return mPixmap.height();
01164   }
01165   else
01166   {
01167     int ht = lb->fontMetrics().boundingRect( 0, 0, 0, 0, Qt::AlignCenter, text() ).height();
01168     return (mPixmap.height() + ht + 10);
01169   }
01170 }
01171 
01172 
01173 int KJanusWidget::IconListItem::width( const QListBox *lb ) const
01174 {
01175   int wt = lb->fontMetrics().boundingRect( 0, 0, 0, 0, Qt::AlignCenter, text() ).width() + 10;
01176   int wp = mPixmap.width() + 10;
01177   int w  = QMAX( wt, wp );
01178   return QMAX( w, mMinimumWidth );
01179 }
01180 
01181 
01182 void KJanusWidget::virtual_hook( int, void* )
01183 { /*BASE::virtual_hook( id, data );*/ }
01184 
01185 
01186 // TODO: In TreeList, if the last child of a node is removed, and there is no corrsponding widget for that node, allow the caller to
01187 // delete the node.
01188 void KJanusWidget::removePage( QWidget *page )
01189 {
01190   if (!d || !d->mPageToInt.contains(page))
01191     return;
01192 
01193   int index = d->mPageToInt[page];
01194 
01195   if ( mFace == TreeList )
01196   {
01197     QMap<QListViewItem*, QWidget *>::Iterator i;
01198     for( i = mTreeListToPageStack.begin(); i != mTreeListToPageStack.end(); ++i )
01199       if (i.data()==page)
01200       {
01201         delete i.key();
01202         mPageStack->removeWidget(page);
01203         mTreeListToPageStack.remove(i);
01204         d->mIntToTitle.remove(index);
01205         d->mPageToInt.remove(page);
01206         d->mIntToPage.remove(index);
01207         break;
01208       }
01209   }
01210   else if ( mFace == IconList )
01211   {
01212     QMap<QListBoxItem*, QWidget *>::Iterator i;
01213     for( i = mIconListToPageStack.begin(); i != mIconListToPageStack.end(); ++i )
01214       if (i.data()==page)
01215       {
01216         delete i.key();
01217         mPageStack->removeWidget(page);
01218         mIconListToPageStack.remove(i);
01219         d->mIntToTitle.remove(index);
01220         d->mPageToInt.remove(page);
01221         d->mIntToPage.remove(index);
01222         break;
01223       }
01224   }
01225   else // Tabbed
01226   {
01227     mTabControl->removePage(page);
01228     d->mPageToInt.remove(page);
01229     d->mIntToPage.remove(index);
01230   }
01231 }
01232 
01233 
01234 QString KJanusWidget::pageTitle(int index) const
01235 {
01236   if (!d || !d->mIntToTitle.contains(index))
01237     return QString::null;
01238   else
01239     return d->mIntToTitle[index];
01240 }
01241 
01242 
01243 QWidget *KJanusWidget::pageWidget(int index) const
01244 {
01245   if (!d || !d->mIntToPage.contains(index))
01246     return 0;
01247   else
01248     return d->mIntToPage[index];
01249 }
01250 
01251 #include "kjanuswidget.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys