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 <tqbitmap.h> 00022 #include <tqgrid.h> 00023 #include <tqhbox.h> 00024 #include <tqheader.h> 00025 #include <tqlabel.h> 00026 #include <tqlayout.h> 00027 #include <tqobjectlist.h> 00028 #include <tqpixmap.h> 00029 #include <tqsplitter.h> 00030 #include <tqtabwidget.h> 00031 #include <tqvbox.h> 00032 #include <tqwidgetstack.h> 00033 #include <tqpainter.h> 00034 #include <tqstyle.h> 00035 00036 #include <tdeapplication.h> 00037 #include <kdialog.h> // Access to some static members 00038 #include <tdelocale.h> 00039 #include <tdeglobal.h> 00040 #include <tdeglobalsettings.h> 00041 #include <kseparator.h> 00042 #include <kdebug.h> 00043 #include "kjanuswidget.h" 00044 #include <tdelistview.h> 00045 #include "kpushbutton.h" 00046 #include "kguiitem.h" 00047 00048 class KJanusWidget::IconListItem : public TQListBoxItem 00049 { 00050 public: 00051 IconListItem( TQListBox *listbox, const TQPixmap &pixmap, 00052 const TQString &text ); 00053 virtual int height( const TQListBox *lb ) const; 00054 virtual int width( const TQListBox *lb ) const; 00055 int expandMinimumWidth( int width ); 00056 void highlight( bool erase ); 00057 00058 protected: 00059 const TQPixmap &defaultPixmap(); 00060 void paint( TQPainter *painter ); 00061 00062 private: 00063 void paintContents( TQPainter *painter ); 00064 00065 TQPixmap 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 TQMap<int,TQWidget*> mIntToPage; 00078 // Reverse dictionary. Used because showPage() may be performance critical. 00079 TQMap<TQWidget*,int> mPageToInt; 00080 // Dictionary of title string associated with page. 00081 TQMap<int, TQString> mIntToTitle; 00082 00083 TQWidget * mListFrame; 00084 TQSplitter * mSplitter; 00085 }; 00086 00087 template class TQPtrList<TQListViewItem>; 00088 00089 00090 KJanusWidget::KJanusWidget( TQWidget *parent, const char *name, int face ) 00091 : TQWidget( parent, name, 0 ), 00092 mValid(false), mPageList(0), 00093 mTitleList(0), mFace(face), mTitleLabel(0), mActivePageWidget(0), 00094 mShowIconsInTreeList(false), d(0) 00095 { 00096 TQVBoxLayout *topLayout = new TQVBoxLayout( this ); 00097 00098 if( mFace == TreeList || mFace == IconList ) 00099 { 00100 d = new KJanusWidgetPrivate; 00101 d->mSplitter = 0; 00102 00103 TQFrame *page; 00104 if( mFace == TreeList ) 00105 { 00106 d->mSplitter = new TQSplitter( this ); 00107 topLayout->addWidget( d->mSplitter, 10 ); 00108 mTreeListResizeMode = TQSplitter::KeepSize; 00109 00110 d->mListFrame = new TQWidget( d->mSplitter ); 00111 TQVBoxLayout *dummy = new TQVBoxLayout( d->mListFrame, 0, KDialog::spacingHint() ); 00112 dummy->setAutoAdd( true ); 00113 mTreeList = new TDEListView( d->mListFrame ); 00114 mTreeList->addColumn( TQString::null ); 00115 mTreeList->header()->hide(); 00116 mTreeList->setRootIsDecorated(true); 00117 mTreeList->setSorting( -1 ); 00118 connect( mTreeList, TQT_SIGNAL(selectionChanged()), TQT_SLOT(slotShowPage()) ); 00119 connect( mTreeList, TQT_SIGNAL(clicked(TQListViewItem *)), TQT_SLOT(slotItemClicked(TQListViewItem *))); 00120 00121 // 00122 // Page area. Title at top with a separator below and a pagestack using 00123 // all available space at bottom. 00124 // 00125 TQFrame *p = new TQFrame( d->mSplitter ); 00126 00127 TQHBoxLayout *hbox = new TQHBoxLayout( p, 0, 0 ); 00128 00129 page = new TQFrame( p ); 00130 hbox->addWidget( page, 10 ); 00131 } 00132 else 00133 { 00134 TQHBoxLayout *hbox = new TQHBoxLayout( topLayout ); 00135 d->mListFrame = new TQWidget( this ); 00136 hbox->addWidget( d->mListFrame ); 00137 00138 ( new TQVBoxLayout( d->mListFrame, 0, 0 ) )->setAutoAdd( true ); 00139 mIconList = new IconListBox( d->mListFrame ); 00140 00141 TQFont listFont( mIconList->font() ); 00142 listFont.setBold( true ); 00143 mIconList->setFont( listFont ); 00144 00145 mIconList->verticalScrollBar()->installEventFilter( this ); 00146 connect( mIconList, TQT_SIGNAL(selectionChanged()), TQT_SLOT(slotShowPage())); 00147 connect( mIconList, TQT_SIGNAL(onItem(TQListBoxItem *)), TQT_SLOT(slotOnItem(TQListBoxItem *))); 00148 00149 hbox->addSpacing( KDialog::marginHint() ); 00150 page = new TQFrame( 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 TQVBoxLayout *vbox = new TQVBoxLayout( page, 0, KDialog::spacingHint() ); 00160 00161 mTitleLabel = new TQLabel( i18n("Empty Page"), page, "KJanusWidgetTitleLabel" ); 00162 vbox->addWidget( mTitleLabel, 0, TQApplication::reverseLayout() ? AlignRight : AlignLeft ); 00163 00164 TQFont titleFont( mTitleLabel->font() ); 00165 titleFont.setBold( true ); 00166 mTitleLabel->setFont( titleFont ); 00167 00168 mTitleSep = new KSeparator( page ); 00169 mTitleSep->setFrameStyle( TQFrame::HLine|TQFrame::Plain ); 00170 vbox->addWidget( mTitleSep ); 00171 00172 mPageStack = new TQWidgetStack( page ); 00173 connect(mPageStack, TQT_SIGNAL(aboutToShow(TQWidget *)), 00174 TQT_SIGNAL(aboutToShowPage(TQWidget *))); 00175 vbox->addWidget( mPageStack, 10 ); 00176 } 00177 else if( mFace == Tabbed ) 00178 { 00179 d = new KJanusWidgetPrivate; 00180 00181 mTabControl = new TQTabWidget( this ); 00182 mTabControl->setMargin (KDialog::marginHint()); 00183 connect(mTabControl, TQT_SIGNAL(currentChanged(TQWidget *)), 00184 TQT_SIGNAL(aboutToShowPage(TQWidget *))); 00185 topLayout->addWidget( mTabControl, 10 ); 00186 } 00187 else if( mFace == Swallow ) 00188 { 00189 mSwallowPage = new TQWidget( this ); 00190 topLayout->addWidget( mSwallowPage, 10 ); 00191 } 00192 else 00193 { 00194 mFace = Plain; 00195 mPlainPage = new TQFrame( this ); 00196 topLayout->addWidget( mPlainPage, 10 ); 00197 } 00198 00199 if ( kapp ) 00200 connect(kapp,TQT_SIGNAL(tdedisplayFontChanged()),TQT_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 TQFrame *KJanusWidget::plainPage() 00220 { 00221 return mPlainPage; 00222 } 00223 00224 00225 int KJanusWidget::face() const 00226 { 00227 return mFace; 00228 } 00229 00230 TQWidget *KJanusWidget::FindParent() 00231 { 00232 if( mFace == Tabbed ) { 00233 return mTabControl; 00234 } 00235 else { 00236 return this; 00237 } 00238 } 00239 00240 TQFrame *KJanusWidget::addPage( const TQStringList &items, const TQString &header, 00241 const TQPixmap &pixmap ) 00242 { 00243 if( !mValid ) 00244 { 00245 kdDebug() << "addPage: Invalid object" << endl; 00246 return 0; 00247 } 00248 00249 TQFrame *page = new TQFrame( FindParent(), "page" ); 00250 addPageWidget( page, items, header, pixmap ); 00251 00252 return page; 00253 } 00254 00255 void KJanusWidget::pageGone( TQObject *obj ) 00256 { 00257 removePage( TQT_TQWIDGET( obj ) ); 00258 } 00259 00260 void KJanusWidget::slotReopen( TQListViewItem * item ) 00261 { 00262 if( item ) 00263 item->setOpen( true ); 00264 } 00265 00266 TQFrame *KJanusWidget::addPage( const TQString &itemName, const TQString &header, 00267 const TQPixmap &pixmap ) 00268 { 00269 TQStringList items; 00270 items << itemName; 00271 return addPage(items, header, pixmap); 00272 } 00273 00274 00275 00276 TQVBox *KJanusWidget::addVBoxPage( const TQStringList &items, 00277 const TQString &header, 00278 const TQPixmap &pixmap ) 00279 { 00280 if( !mValid ) 00281 { 00282 kdDebug() << "addPage: Invalid object" << endl; 00283 return 0; 00284 } 00285 00286 TQVBox *page = new TQVBox(FindParent() , "page" ); 00287 page->setSpacing( KDialog::spacingHint() ); 00288 addPageWidget( page, items, header, pixmap ); 00289 00290 return page; 00291 } 00292 00293 TQVBox *KJanusWidget::addVBoxPage( const TQString &itemName, 00294 const TQString &header, 00295 const TQPixmap &pixmap ) 00296 { 00297 TQStringList items; 00298 items << itemName; 00299 return addVBoxPage(items, header, pixmap); 00300 } 00301 00302 TQHBox *KJanusWidget::addHBoxPage( const TQStringList &items, 00303 const TQString &header, 00304 const TQPixmap &pixmap ) 00305 { 00306 if( !mValid ) { 00307 kdDebug() << "addPage: Invalid object" << endl; 00308 return 0; 00309 } 00310 00311 TQHBox *page = new TQHBox(FindParent(), "page"); 00312 page->setSpacing( KDialog::spacingHint() ); 00313 addPageWidget( page, items, header, pixmap ); 00314 00315 return page; 00316 } 00317 00318 TQHBox *KJanusWidget::addHBoxPage( const TQString &itemName, 00319 const TQString &header, 00320 const TQPixmap &pixmap ) 00321 { 00322 TQStringList items; 00323 items << itemName; 00324 return addHBoxPage(items, header, pixmap); 00325 } 00326 00327 TQGrid *KJanusWidget::addGridPage( int n, Orientation dir, 00328 const TQStringList &items, 00329 const TQString &header, 00330 const TQPixmap &pixmap ) 00331 { 00332 if( !mValid ) 00333 { 00334 kdDebug() << "addPage: Invalid object" << endl; 00335 return 0; 00336 } 00337 00338 TQGrid *page = new TQGrid( n, dir, FindParent(), "page" ); 00339 page->setSpacing( KDialog::spacingHint() ); 00340 addPageWidget( page, items, header, pixmap ); 00341 00342 return page; 00343 } 00344 00345 00346 TQGrid *KJanusWidget::addGridPage( int n, Orientation dir, 00347 const TQString &itemName, 00348 const TQString &header, 00349 const TQPixmap &pixmap ) 00350 { 00351 TQStringList items; 00352 items << itemName; 00353 return addGridPage(n, dir, items, header, pixmap); 00354 } 00355 00356 void KJanusWidget::InsertTreeListItem(const TQStringList &items, const TQPixmap &pixmap, TQFrame *page) 00357 { 00358 bool isTop = true; 00359 TQListViewItem *curTop = 0, *child, *last, *newChild; 00360 unsigned int index = 1; 00361 TQStringList curPath; 00362 00363 for ( TQStringList::ConstIterator it = items.begin(); it != items.end(); ++it, index++ ) { 00364 TQString 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 TQListViewItem(mTreeList, name); 00384 else 00385 newChild = new TQListViewItem(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 TQListViewItem(mTreeList, last, name); 00403 else 00404 newChild = new TQListViewItem(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 TQString key = curPath.join("_/_"); 00416 if (mFolderIconMap.contains(key)) { 00417 TQPixmap 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( TQFrame *page, const TQStringList &items, 00431 const TQString &header,const TQPixmap &pixmap ) 00432 { 00433 connect(page, TQT_SIGNAL(destroyed(TQObject*)), TQT_SLOT(pageGone(TQObject*))); 00434 00435 if( mFace == Tabbed ) 00436 { 00437 mTabControl->addTab (page, items.last()); 00438 d->mIntToPage[d->mNextPageIndex] = static_cast<TQWidget*>(page); 00439 d->mPageToInt[static_cast<TQWidget*>(page)] = d->mNextPageIndex; 00440 d->mNextPageIndex++; 00441 } 00442 else if( mFace == TreeList || mFace == IconList ) 00443 { 00444 d->mIntToPage[d->mNextPageIndex] = static_cast<TQWidget*>(page); 00445 d->mPageToInt[static_cast<TQWidget*>(page)] = d->mNextPageIndex; 00446 mPageStack->addWidget( page, 0 ); 00447 00448 if (items.isEmpty()) { 00449 kdDebug() << "Invalid TQStringList, 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 TQString 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 TQString lastName = items.last(); 00473 const TQString &title = (!header.isNull() ? header : lastName); 00474 TQRect 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 TQStringList &path, const TQPixmap &pixmap) 00494 { 00495 TQString key = path.join("_/_"); 00496 mFolderIconMap.insert(key,pixmap); 00497 } 00498 00499 00500 00501 bool KJanusWidget::setSwallowedWidget( TQWidget *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 TQGridLayout *gbox = new TQGridLayout( mSwallowPage, 1, 1, 0 ); 00514 00515 // 00516 // Hide old children 00517 // 00518 TQObjectList l = mSwallowPage->childrenListObject(); // silence please 00519 for( uint i=0; i < l.count(); i++ ) 00520 { 00521 TQObject *o = l.at(i); 00522 if( o->isWidgetType() ) 00523 { 00524 ((TQWidget*)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( TQT_BASE_OBJECT(widget->parent()) != TQT_BASE_OBJECT(mSwallowPage) ) 00540 { 00541 widget->reparent( mSwallowPage, 0, TQPoint(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 TQListViewItem *node = mTreeList->selectedItem(); 00561 if( !node ) { return false; } 00562 00563 TQWidget *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 TQListBoxItem *node = mIconList->item( mIconList->currentItem() ); 00570 if( !node ) { return false; } 00571 TQWidget *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( TQWidget *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 TQMap<TQListViewItem *, TQWidget *>::Iterator it; 00610 for (it = mTreeListToPageStack.begin(); it != mTreeListToPageStack.end(); ++it){ 00611 TQListViewItem *key = it.key(); 00612 TQWidget *val = it.data(); 00613 if (val == w) { 00614 mTreeList->setSelected(key, true ); 00615 break; 00616 } 00617 } 00618 } 00619 else 00620 { 00621 TQMap<TQListBoxItem *, TQWidget *>::Iterator it; 00622 for (it = mIconListToPageStack.begin(); it != mIconListToPageStack.end(); ++it){ 00623 TQListBoxItem *key = it.key(); 00624 TQWidget *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 TQListViewItem *node = mTreeList->selectedItem(); 00650 if( !node ) { return -1; } 00651 TQWidget *stackItem = mTreeListToPageStack[node]; 00652 return d->mPageToInt[stackItem]; 00653 } 00654 else if (mFace == IconList) { 00655 TQListBoxItem *node = mIconList->item( mIconList->currentItem() ); 00656 if( !node ) { return false; } 00657 TQWidget *stackItem = mIconListToPageStack[node]; 00658 return d->mPageToInt[stackItem]; 00659 } 00660 else if( mFace == Tabbed ) { 00661 TQWidget *widget = mTabControl->currentPage(); 00662 return ( !widget ? -1 : d->mPageToInt[widget] ); 00663 } 00664 else { 00665 return -1; 00666 } 00667 } 00668 00669 00670 int KJanusWidget::pageIndex( TQWidget *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 TQFrame so I check for that. 00686 // 00687 if( widget->isA(TQFRAME_OBJECT_NAME_STRING) ) 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( TDEGlobalSettings::generalFont() ); 00707 TQFont titleFont( mTitleLabel->font() ); 00708 titleFont.setBold( true ); 00709 mTitleLabel->setFont( titleFont ); 00710 } 00711 00712 if( mFace == IconList ) 00713 { 00714 TQFont 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(TQListViewItem *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(TQListBoxItem *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 TQSize KJanusWidget::minimumSizeHint() const 00762 { 00763 if( mFace == TreeList || mFace == IconList ) 00764 { 00765 TQSize s1( KDialog::spacingHint(), KDialog::spacingHint()*2 ); 00766 TQSize s2(0,0); 00767 TQSize s3(0,0); 00768 TQSize s4( mPageStack->sizeHint() ); 00769 00770 if( mFace == TreeList ) 00771 { 00772 s1.rwidth() += style().pixelMetric( TQStyle::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 = TQMAX( h1, s2.rheight() ); 00793 00794 return TQSize( s1.width()+s2.width()+TQMAX(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 TQSize( 100, 100 ); // Should never happen though. 00811 } 00812 00813 } 00814 00815 00816 TQSize 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 TQSplitter::KeepSize : TQSplitter::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, TQT_SIGNAL( collapsed( TQListViewItem * ) ), this, TQT_SLOT( slotReopen( TQListViewItem * ) ) ); 00860 else 00861 disconnect( mTreeList, TQT_SIGNAL( collapsed( TQListViewItem * ) ), this, TQT_SLOT( slotReopen( TQListViewItem * ) ) ); 00862 00863 for( TQListViewItem * item = mTreeList->firstChild(); item; item = item->itemBelow() ) 00864 item->setOpen( true ); 00865 } 00866 } 00867 00868 void KJanusWidget::addWidgetBelowList( TQWidget * widget ) 00869 { 00870 if( ( mFace == TreeList || mFace == IconList ) && d->mListFrame ) 00871 { 00872 widget->reparent( d->mListFrame, TQPoint() ); 00873 } 00874 } 00875 00876 void KJanusWidget::addButtonBelowList( const TQString & text, TQObject * recv, const char * slot ) 00877 { 00878 if( ( mFace == TreeList || mFace == IconList ) && d->mListFrame ) 00879 { 00880 TQPushButton * button = new TQPushButton( text, d->mListFrame, "KJanusWidget::buttonBelowList" ); 00881 connect( button, TQT_SIGNAL( clicked() ), recv, slot ); 00882 } 00883 } 00884 00885 void KJanusWidget::addButtonBelowList( const KGuiItem & item, TQObject * 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, TQT_SIGNAL( clicked() ), recv, slot ); 00891 } 00892 } 00893 00894 void KJanusWidget::showEvent( TQShowEvent * ) 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( TQObject *o, TQEvent *e ) 00910 { 00911 if( e->type() == TQEvent::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() == TQEvent::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 TQWidget::eventFilter( o, e ); 00931 } 00932 00933 00934 00935 // 00936 // Code for the icon list box 00937 // 00938 00939 00940 KJanusWidget::IconListBox::IconListBox( TQWidget *parent, const char *name, 00941 WFlags f ) 00942 :TDEListBox( 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( TQListBoxItem *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( TQListBoxItem *i = item(0); i; i = i->next() ) 00969 { 00970 int w = ((IconListItem *)i)->width(this); 00971 maxWidth = TQMAX( w, maxWidth ); 00972 } 00973 00974 for( TQListBoxItem *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( TQEvent *ev ) 01010 { 01011 TDEListBox::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(TQListBoxItem *qitem) 01022 { 01023 TDEListBox::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( TQListBox *listbox, const TQPixmap &pixmap, 01050 const TQString &text ) 01051 : TQListBoxItem( 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 = TQMAX( mMinimumWidth, width ); 01067 return mMinimumWidth; 01068 } 01069 01070 01071 void KJanusWidget::IconListItem::highlight( bool erase ) 01072 { 01073 // FIXME: Add configuration option to disable highlighting 01074 // For now, always disable highlighting 01075 erase = true; 01076 01077 TQRect r = listBox()->itemRect( this ); 01078 r.addCoords( 1, 1, -1, -1 ); 01079 01080 TQPainter p( listBox()->viewport() ); 01081 p.setClipRegion( r ); 01082 01083 const TQColorGroup &cg = listBox()->colorGroup(); 01084 if ( erase ) 01085 { 01086 p.setPen( cg.base() ); 01087 p.setBrush( cg.base() ); 01088 p.drawRect( r ); 01089 } 01090 else 01091 { 01092 p.setBrush( cg.highlight().light( 120 ) ); 01093 p.drawRect( r ); 01094 01095 p.setPen( cg.highlight().dark( 140 ) ); 01096 p.drawRect( r ); 01097 } 01098 01099 p.setPen( cg.foreground() ); 01100 p.translate( r.x() - 1, r.y() - 1 ); 01101 paintContents( &p ); 01102 } 01103 01104 01105 const TQPixmap &KJanusWidget::IconListItem::defaultPixmap() 01106 { 01107 static TQPixmap *pix=0; 01108 if( !pix ) 01109 { 01110 pix = new TQPixmap( 32, 32 ); 01111 TQPainter p( pix ); 01112 p.eraseRect( 0, 0, pix->width(), pix->height() ); 01113 p.setPen( Qt::red ); 01114 p.drawRect ( 0, 0, pix->width(), pix->height() ); 01115 p.end(); 01116 01117 TQBitmap mask( pix->width(), pix->height(), true ); 01118 mask.fill( Qt::black ); 01119 p.begin( &mask ); 01120 p.setPen( Qt::white ); 01121 p.drawRect ( 0, 0, pix->width(), pix->height() ); 01122 p.end(); 01123 01124 pix->setMask( mask ); 01125 } 01126 return *pix; 01127 } 01128 01129 01130 void KJanusWidget::IconListItem::paint( TQPainter *painter ) 01131 { 01132 TQRect itemPaintRegion( listBox()->itemRect( this ) ); 01133 TQRect r( 1, 1, itemPaintRegion.width() - 2, itemPaintRegion.height() - 2); 01134 01135 if ( isSelected() ) 01136 { 01137 painter->eraseRect( r ); 01138 01139 painter->save(); 01140 painter->setPen( listBox()->colorGroup().highlight().dark( 160 ) ); 01141 painter->drawRect( r ); 01142 painter->restore(); 01143 } 01144 01145 paintContents( painter ); 01146 } 01147 01148 01149 void KJanusWidget::IconListItem::paintContents( TQPainter *painter ) 01150 { 01151 TQFontMetrics fm = painter->fontMetrics(); 01152 int ht = fm.boundingRect( 0, 0, 0, 0, Qt::AlignCenter, text() ).height(); 01153 int wp = mPixmap.width(); 01154 int hp = mPixmap.height(); 01155 painter->drawPixmap( (mMinimumWidth - wp) / 2, 5, mPixmap ); 01156 01157 if( !text().isEmpty() ) 01158 { 01159 painter->drawText( 1, hp + 7, mMinimumWidth - 2, ht, Qt::AlignCenter, text() ); 01160 } 01161 } 01162 01163 int KJanusWidget::IconListItem::height( const TQListBox *lb ) const 01164 { 01165 if( text().isEmpty() ) 01166 { 01167 return mPixmap.height(); 01168 } 01169 else 01170 { 01171 int ht = lb->fontMetrics().boundingRect( 0, 0, 0, 0, Qt::AlignCenter, text() ).height(); 01172 return (mPixmap.height() + ht + 10); 01173 } 01174 } 01175 01176 01177 int KJanusWidget::IconListItem::width( const TQListBox *lb ) const 01178 { 01179 int wt = lb->fontMetrics().boundingRect( 0, 0, 0, 0, Qt::AlignCenter, text() ).width() + 10; 01180 int wp = mPixmap.width() + 10; 01181 int w = TQMAX( wt, wp ); 01182 return TQMAX( w, mMinimumWidth ); 01183 } 01184 01185 01186 void KJanusWidget::virtual_hook( int, void* ) 01187 { /*BASE::virtual_hook( id, data );*/ } 01188 01189 01190 // 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 01191 // delete the node. 01192 void KJanusWidget::removePage( TQWidget *page ) 01193 { 01194 if (!d || !d->mPageToInt.contains(page)) 01195 return; 01196 01197 int index = d->mPageToInt[page]; 01198 01199 if ( mFace == TreeList ) 01200 { 01201 TQMap<TQListViewItem*, TQWidget *>::Iterator i; 01202 for( i = mTreeListToPageStack.begin(); i != mTreeListToPageStack.end(); ++i ) 01203 if (i.data()==page) 01204 { 01205 delete i.key(); 01206 mPageStack->removeWidget(page); 01207 mTreeListToPageStack.remove(i); 01208 d->mIntToTitle.remove(index); 01209 d->mPageToInt.remove(page); 01210 d->mIntToPage.remove(index); 01211 break; 01212 } 01213 } 01214 else if ( mFace == IconList ) 01215 { 01216 TQMap<TQListBoxItem*, TQWidget *>::Iterator i; 01217 for( i = mIconListToPageStack.begin(); i != mIconListToPageStack.end(); ++i ) 01218 if (i.data()==page) 01219 { 01220 delete i.key(); 01221 mPageStack->removeWidget(page); 01222 mIconListToPageStack.remove(i); 01223 d->mIntToTitle.remove(index); 01224 d->mPageToInt.remove(page); 01225 d->mIntToPage.remove(index); 01226 break; 01227 } 01228 } 01229 else // Tabbed 01230 { 01231 mTabControl->removePage(page); 01232 d->mPageToInt.remove(page); 01233 d->mIntToPage.remove(index); 01234 } 01235 } 01236 01237 01238 TQString KJanusWidget::pageTitle(int index) const 01239 { 01240 if (!d || !d->mIntToTitle.contains(index)) 01241 return TQString::null; 01242 else 01243 return d->mIntToTitle[index]; 01244 } 01245 01246 01247 TQWidget *KJanusWidget::pageWidget(int index) const 01248 { 01249 if (!d || !d->mIntToPage.contains(index)) 01250 return 0; 01251 else 01252 return d->mIntToPage[index]; 01253 } 01254 01255 #include "kjanuswidget.moc"