• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

Kate

katecompletiontree.cpp

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