• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Kate

katecompletiontree.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2006 Hamish Rodda <rodda@kde.org>
00003    Copyright (C) 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
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 version 2 as published by the Free Software Foundation.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public 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
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "katecompletiontree.h"
00021 
00022 #include <QtGui/QHeaderView>
00023 #include <QtGui/QScrollBar>
00024 #include <QVector>
00025 #include <QTimer>
00026 #include <QApplication>
00027 #include <QDesktopWidget>
00028 
00029 #include "kateview.h"
00030 #include "katerenderer.h"
00031 #include "kateconfig.h"
00032 
00033 #include "katecompletionwidget.h"
00034 #include "katecompletiondelegate.h"
00035 #include "katecompletionmodel.h"
00036 
00037 KateCompletionTree::KateCompletionTree(KateCompletionWidget* parent)
00038   : ExpandingTree(parent)
00039 {
00040   m_scrollingEnabled = true;
00041   header()->hide();
00042   setRootIsDecorated(false);
00043   setIndentation(0);
00044   setFrameStyle(QFrame::NoFrame);
00045   setAllColumnsShowFocus(true);
00046   setAlternatingRowColors(true);
00047   //We need ScrollPerItem, because ScrollPerPixel is too slow with a very large competion-list(see KDevelop).
00048   setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
00049 
00050   m_resizeTimer = new QTimer(this);
00051   m_resizeTimer->setSingleShot(true);
00052 
00053   connect(m_resizeTimer, SIGNAL(timeout()), this, SLOT(resizeColumnsSlot()));
00054   
00055   // Provide custom highlighting to completion entries
00056   setItemDelegate(new KateCompletionDelegate(widget()->model(), widget()));
00057   
00059   //connect(widget()->model(), SIGNAL(contentGeometryChanged()), this, SLOT(resizeColumnsSlot()));
00060 
00061   // Prevent user from expanding / collapsing with the mouse
00062   setItemsExpandable(false);
00063   setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00064 }
00065 
00066 void KateCompletionTree::currentChanged ( const QModelIndex & current, const QModelIndex & previous ) {
00067   widget()->model()->rowSelected(current);
00068   ExpandingTree::currentChanged(current, previous);
00069 }
00070 
00071 void KateCompletionTree::setScrollingEnabled(bool enabled) {
00072   m_scrollingEnabled = enabled;
00073 }
00074 
00075 void KateCompletionTree::scrollContentsBy( int dx, int dy )
00076 {
00077   if(m_scrollingEnabled)
00078     QTreeView::scrollContentsBy(dx, dy);
00079 
00080   if (isVisible())
00081     m_resizeTimer->start(300);
00082 }
00083 
00084 int KateCompletionTree::columnTextViewportPosition ( int column ) const {
00085   int ret = columnViewportPosition(column);
00086   QModelIndex i = model()->index(0, column, QModelIndex());
00087   QModelIndex base = model()->index(0, 0, QModelIndex());
00088   
00089   //If it's just a group header, use the first child
00090   if(base.isValid() && model()->rowCount(base))
00091     i = base.child(0, column);
00092     
00093   if(i.isValid()) {
00094     QIcon icon = i.data(Qt::DecorationRole).value<QIcon>();
00095     if(!icon.isNull())
00096       ret += icon.actualSize(sizeHintForIndex(i)).width();
00097   }
00098   return ret;
00099 }
00100 
00101 KateCompletionWidget * KateCompletionTree::widget( ) const
00102 {
00103   return static_cast<KateCompletionWidget*>(const_cast<QObject*>(parent()));
00104 }
00105 
00106 void KateCompletionTree::resizeColumnsSlot()
00107 {
00108   if(model())
00109     resizeColumns();
00110 }
00111 
00112 void KateCompletionTree::resizeColumns(bool fromResizeEvent, bool firstShow, bool forceResize)
00113 {
00114   static bool preventRecursion = false;
00115   if (preventRecursion)
00116     return;
00117   
00118   if(firstShow)
00119     forceResize = true;
00120 
00121   preventRecursion = true;
00122 
00123   widget()->setUpdatesEnabled(false);
00124 
00125   int modelIndexOfName = kateModel()->translateColumn(KTextEditor::CodeCompletionModel::Name);
00126   int oldIndentWidth = columnViewportPosition(modelIndexOfName);
00127 
00129 
00130   int numColumns = model()->columnCount();
00131   
00132   QVector<int> columnSize(numColumns, 5);
00133 
00134   int currentYPos = 0;
00135 
00136   QModelIndex current = indexAt(QPoint(1,1));
00137   if( current.child(0,0).isValid() ) { //If the index has children, it is a group-label. Then we should start with it's first child.
00138     currentYPos += sizeHintForIndex(current).height();
00139     current = current.child(0,0);
00140   }
00141 
00142   int num = 0;
00143   bool changed = false;
00144   
00145   while( current.isValid() && currentYPos < height() )
00146   {
00147 //     kDebug() << current.row() << "out of" << model()->rowCount(current.parent()) << "in" << current.parent().data(Qt::DisplayRole);
00148     currentYPos += sizeHintForIndex(current).height();
00149 //     itemDelegate()->sizeHint(QStyleOptionViewItem(), current).isValid() && itemDelegate()->sizeHint(QStyleOptionViewItem(), current).intersects(visibleViewportRect)
00150     changed = true;
00151     num++;
00152     for( int a = 0; a < numColumns; a++ )
00153     {
00154       QSize s = sizeHintForIndex (current.sibling(current.row(), a));
00155 //       kDebug() << "size-hint for" << current.row() << a << ":" << s << current.sibling(current.row(), a).data(Qt::DisplayRole);
00156       if( s.width() > columnSize[a] && s.width() < 2000 )
00157         columnSize[a] = s.width();
00158       else if( s.width() > 2000 )
00159         kDebug( 13035 ) << "got invalid size-hint of width " << s.width();
00160     }
00161 
00162     QModelIndex oldCurrent = current;
00163     current = current.sibling(current.row()+1, 0);
00164     
00165     //Are we at the end of a group? If yes, move on into the next group
00166     if( !current.isValid() && oldCurrent.parent().isValid() ) {
00167       current = oldCurrent.parent().sibling( oldCurrent.parent().row()+1, 0 );
00168       if( current.isValid() && current.child(0,0).isValid() ) {
00169     currentYPos += sizeHintForIndex(current).height();
00170         current = current.child(0,0);
00171       }
00172     }
00173   }
00174 
00175   int totalColumnsWidth = 0, originalViewportWidth = viewport()->width();
00176   
00177   int maxWidth = (QApplication::desktop()->screenGeometry(widget()->view()).width()*3) / 4;
00178 
00180   //This contains several hacks to reduce the amount of resizing that happens. Generally,
00181   //resizes only happen if a) More than a specific amount of space is saved by the resize, or
00182   //b) the resizing is required so the list can show all of its contents.
00183   int minimumResize = 0;
00184   int maximumResize = 0;
00185   
00186   if( changed ) {
00187 
00188     for( int n = 0; n < numColumns; n++ ) {
00189       totalColumnsWidth += columnSize[n];
00190       
00191       int diff = columnSize[n] - columnWidth(n);
00192       if( diff < minimumResize )
00193         minimumResize = diff;
00194       if( diff > maximumResize )
00195         maximumResize = diff;
00196     }
00197     
00198     int noReduceTotalWidth = 0; //The total width of the widget of no columns are reduced
00199     for( int n = 0; n < numColumns; n++ ) {
00200       if(columnSize[n] < columnWidth(n))
00201         noReduceTotalWidth += columnWidth(n);
00202       else
00203         noReduceTotalWidth += columnSize[n];
00204     }
00205 
00206     //Check whether we can afford to reduce none of the columns
00207     //Only reduce size if we widget would else be too wide.
00208   bool noReduce = noReduceTotalWidth < maxWidth && !forceResize;
00209 
00210     if(noReduce) {
00211       totalColumnsWidth = 0;
00212       for( int n = 0; n < numColumns; n++ ) {
00213         if(columnSize[n] < columnWidth(n))
00214           columnSize[n] = columnWidth(n);
00215 
00216         totalColumnsWidth += columnSize[n];
00217       }
00218     }
00219 
00220     if( minimumResize > -40 && maximumResize == 0 && !forceResize ) {
00221       //No column needs to be exanded, and no column needs to be reduced by more than 40 pixels.
00222       //To prevent flashing, do not resize at all.
00223       totalColumnsWidth = 0;
00224       for( int n = 0; n < numColumns; n++ ) {
00225         columnSize[n] = columnWidth(n);
00226         totalColumnsWidth += columnSize[n];
00227       }
00228     } else {
00229 //       viewport()->resize( 5000, viewport()->height() );
00230       for( int n = 0; n < numColumns; n++ ) {
00231         setColumnWidth(n, columnSize[n]);
00232       }
00233 //       kDebug() << "resizing viewport to" << totalColumnsWidth;
00234       viewport()->resize( totalColumnsWidth, viewport()->height() );
00235     }
00236   }
00237 
00239   
00240   int scrollBarWidth = verticalScrollBar()->width();
00241   
00242   int newIndentWidth = columnViewportPosition(modelIndexOfName);
00243 
00244   int newWidth = qMin(maxWidth, qMax(75, totalColumnsWidth));
00245   
00246   if(newWidth == maxWidth)
00247     setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
00248   else
00249     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00250     
00251   if(maximumResize > 0 || forceResize || oldIndentWidth != newIndentWidth) {
00252   
00253     //   kDebug() << geometry() << "newWidth" << newWidth << "current width" << width() << "target width" << newWidth + scrollBarWidth;
00254     
00255     if((newWidth + scrollBarWidth) != width() && originalViewportWidth != totalColumnsWidth)
00256     {
00257         widget()->resize(newWidth + scrollBarWidth + 2, widget()->height());
00258         resize(newWidth + scrollBarWidth, widget()->height()- (2*widget()->frameWidth()));
00259     }
00260     
00261     //   kDebug() << "created geometry:" << widget()->geometry() << geometry() << "newWidth" << newWidth << "viewport" << viewport()->width();
00262     
00263     if( viewport()->width() > totalColumnsWidth ) //Set the size of the last column to fill the whole rest of the widget
00264     setColumnWidth(numColumns-1, viewport()->width() - columnViewportPosition(numColumns-1));
00265     
00266     /*  for(int a = 0; a < numColumns; ++a)
00267         kDebug() << "column" << a << columnWidth(a) << "target:" << columnSize[a];*/
00268     
00269     if (oldIndentWidth != newIndentWidth)
00270         if(widget()->updatePosition() && !forceResize) {
00271         preventRecursion = false;
00272         resizeColumns(false, true, true);
00273         }
00274   }
00275     
00276   widget()->setUpdatesEnabled(true);
00277   
00278   preventRecursion = false;
00279 }
00280 
00281 QStyleOptionViewItem KateCompletionTree::viewOptions( ) const
00282 {
00283   QStyleOptionViewItem opt = QTreeView::viewOptions();
00284 
00285   opt.font = widget()->view()->renderer()->config()->font();
00286 
00287   return opt;
00288 }
00289 
00290 KateCompletionModel * KateCompletionTree::kateModel( ) const
00291 {
00292   return static_cast<KateCompletionModel*>(model());
00293 }
00294 
00295 bool KateCompletionTree::nextCompletion()
00296 {
00297   QModelIndex current;
00298   QModelIndex firstCurrent = currentIndex();
00299 
00300   do {
00301     QModelIndex oldCurrent = currentIndex();
00302 
00303     current = moveCursor(MoveDown, Qt::NoModifier);
00304 
00305     if (current != oldCurrent && current.isValid()) {
00306       setCurrentIndex(current);
00307     } else {
00308       if (firstCurrent.isValid())
00309         setCurrentIndex(firstCurrent);
00310       return false;
00311     }
00312 
00313   } while (!kateModel()->indexIsItem(current));
00314 
00315   return true;
00316 }
00317 
00318 bool KateCompletionTree::previousCompletion()
00319 {
00320   QModelIndex current;
00321   QModelIndex firstCurrent = currentIndex();
00322 
00323   do {
00324     QModelIndex oldCurrent = currentIndex();
00325 
00326     current = moveCursor(MoveUp, Qt::NoModifier);
00327 
00328     if (current != oldCurrent && current.isValid()) {
00329       setCurrentIndex(current);
00330 
00331     } else {
00332       if (firstCurrent.isValid())
00333         setCurrentIndex(firstCurrent);
00334       return false;
00335     }
00336 
00337   } while (!kateModel()->indexIsItem(current));
00338 
00339   return true;
00340 }
00341 
00342 bool KateCompletionTree::pageDown( )
00343 {
00344   QModelIndex old = currentIndex();
00345   
00346   QModelIndex current = moveCursor(MovePageDown, Qt::NoModifier);
00347 
00348   if (current.isValid()) {
00349     setCurrentIndex(current);
00350     if (!kateModel()->indexIsItem(current))
00351       if (!nextCompletion())
00352         previousCompletion();
00353   }
00354 
00355   return current != old;
00356 }
00357 
00358 bool KateCompletionTree::pageUp( )
00359 {
00360   QModelIndex old = currentIndex();
00361   QModelIndex current = moveCursor(MovePageUp, Qt::NoModifier);
00362 
00363   if (current.isValid()) {
00364     setCurrentIndex(current);
00365     if (!kateModel()->indexIsItem(current))
00366       if (!previousCompletion())
00367         nextCompletion();
00368   }
00369   return current != old;
00370 }
00371 
00372 void KateCompletionTree::top( )
00373 {
00374   QModelIndex current = moveCursor(MoveHome, Qt::NoModifier);
00375   setCurrentIndex(current);
00376 
00377   if (current.isValid()) {
00378     setCurrentIndex(current);
00379     if (!kateModel()->indexIsItem(current))
00380       nextCompletion();
00381   }
00382 }
00383 
00384 void KateCompletionTree::scheduleUpdate()
00385 {
00386     m_resizeTimer->start(300);
00387 }
00388 
00389 void KateCompletionTree::bottom( )
00390 {
00391   QModelIndex current = moveCursor(MoveEnd, Qt::NoModifier);
00392   setCurrentIndex(current);
00393 
00394   if (current.isValid()) {
00395     setCurrentIndex(current);
00396     if (!kateModel()->indexIsItem(current))
00397       previousCompletion();
00398   }
00399 }
00400 
00401 #include "katecompletiontree.moc"

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal