1 /******************************************************************************
3 * This file is part of libkdepim.
5 * Copyright (C) 2008 Szymon Tomasz Stefanek <pragma@kvirc.net>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
22 *****************************************************************************/
24 #include "treewidget.h"
28 #include <KConfigGroup>
31 #include <QHeaderView>
37 #define KPIM_TREEWIDGET_DEFAULT_CONFIG_KEY "TreeWidgetLayout"
39 TreeWidget::TreeWidget( QWidget
* parent
, const char * name
)
40 : QTreeWidget( parent
)
42 setObjectName( name
);
45 header()->setMovable( true );
47 setManualColumnHidingEnabled( true );
49 // At the moment of writing (25.11.2008) there is a bug in Qt
50 // which causes an assertion failure in animated views when
51 // the animated item is deleted. The bug notification has been
52 // sent to qt-bugs. For the moment we keep animations explicitly disabled.
53 // FIXME: Re-enable animations once the qt bug is fixed.
57 void TreeWidget::changeEvent( QEvent
*e
)
59 QTreeWidget::changeEvent( e
);
61 if ( e
->type() == QEvent::StyleChange
)
63 // At the moment of writing (25.11.2008) there is a bug in Qt
64 // which causes an assertion failure in animated views when
65 // the animated item is deleted. The bug notification has been
66 // sent to qt-bugs. For the moment we keep animations explicitly disabled.
67 // FIXME: Re-enable animations once the qt bug is fixed.
72 bool TreeWidget::saveLayout( KConfigGroup
&group
, const QString
&keyName
) const
75 keyName
.isEmpty() ? QString( KPIM_TREEWIDGET_DEFAULT_CONFIG_KEY
) : keyName
,
76 QVariant( header()->saveState().toHex() )
82 bool TreeWidget::saveLayout( KConfig
* config
, const QString
&groupName
, const QString
&keyName
) const
84 if( !config
|| groupName
.isEmpty() )
87 KConfigGroup
group( config
, groupName
);
88 return saveLayout( group
, keyName
);
91 bool TreeWidget::restoreLayout( KConfigGroup
&group
, const QString
&keyName
)
93 // Restore the view column order, width and visibility
94 QByteArray state
= group
.readEntry(
95 keyName
.isEmpty() ? QString( KPIM_TREEWIDGET_DEFAULT_CONFIG_KEY
) : keyName
,
96 QVariant( QVariant::ByteArray
)
98 state
= QByteArray::fromHex( state
);
100 if( state
.isEmpty() )
103 int cc
= header()->count();
105 // Qt writes also some options that can be set only
106 // programmatically. This can drive you crazy if you
107 // first setup the view and then restore the layout:
108 // it will overwrite your previous settings...
110 bool sectionsWereClickable
= header()->isClickable();
111 bool sectionsWereMovable
= header()->isMovable();
112 bool sortIndicatorWasShown
= header()->isSortIndicatorShown();
113 Qt::Alignment originalDefaultAlignment
= header()->defaultAlignment();
114 //int defaultSectionSize = header()->defaultSectionSize();
115 int minimumSectionSize
= header()->minimumSectionSize();
116 bool cascadingSectionResizes
= header()->cascadingSectionResizes();
117 QVector
<QHeaderView::ResizeMode
> resizeModes( cc
);
118 for ( int i
= 0 ; i
< cc
; ++i
) {
119 resizeModes
[ i
] = header()->resizeMode( i
);
122 // Qt (4.4) will perform a layout based on the stored column sizes
123 // when restoreState() is called. However, there is an issue
124 // related to the last section: the restoreState() call will
125 // preserve the _current_ (pre-restoreState()-call) width
126 // of the last section if that is actually greater than the stored
127 // value. This is very likely to throw the last section out of
128 // the view and cause a horizontal scroll bar to appear even
129 // if it wasn't present when saveState() was called.
130 // This seems to be a Qt buggie and we workaround it by
131 // setting all the sections sizes to something very small
132 // just before calling restoreState().
134 // we also need to save the current sections sizes in order to remain
135 // consistent if restoreState() fails for some reason.
136 QVector
<int> savedSizes( cc
);
137 for ( int i
= 0 ; i
< cc
; i
++ )
139 savedSizes
[ i
] = header()->sectionSize( i
);
140 header()->resizeSection( i
, 10 );
143 if ( !header()->restoreState( state
) )
145 // failed: be consistent and restore the section sizes before returning
146 for ( int c
= 0 ; c
< cc
; c
++ )
147 header()->resizeSection( c
, savedSizes
[ c
] );
151 header()->setClickable( sectionsWereClickable
);
152 header()->setMovable( sectionsWereMovable
);
153 header()->setSortIndicatorShown( sortIndicatorWasShown
);
154 header()->setDefaultAlignment( originalDefaultAlignment
);
155 header()->setMinimumSectionSize( minimumSectionSize
);
156 header()->setCascadingSectionResizes( cascadingSectionResizes
);
157 for ( int i
= 0 ; i
< cc
; ++i
) {
158 header()->setResizeMode( i
, resizeModes
[ i
] );
161 // FIXME: This would cause the sections to be resized and thus
162 // can't be reliably reset after the configuration
163 // has been read. Can do nothing about that except warning
164 // the user in the docs.
165 //header()->setDefaultSectionSize( defaultSectionSize );
170 bool TreeWidget::restoreLayout( KConfig
* config
, const QString
&groupName
, const QString
&keyName
)
172 if( !config
|| groupName
.isEmpty() )
175 if ( !config
->hasGroup( groupName
) )
178 KConfigGroup
group( config
, groupName
);
179 return restoreLayout( group
, keyName
);
182 void TreeWidget::setManualColumnHidingEnabled( bool enable
)
186 header()->setContextMenuPolicy( Qt::CustomContextMenu
); // make sure it's true
187 QObject::connect( header(), SIGNAL(customContextMenuRequested(QPoint
)),
188 this, SLOT(slotHeaderContextMenuRequested(QPoint
)) );
190 if ( mEnableManualColumnHiding
)
191 QObject::disconnect( header(), SIGNAL(customContextMenuRequested(QPoint
)),
192 this, SLOT(slotHeaderContextMenuRequested(QPoint
)) );
195 mEnableManualColumnHiding
= enable
;
198 void TreeWidget::setColumnHidden( int logicalIndex
, bool hide
)
200 if ( header()->isSectionHidden( logicalIndex
) == hide
)
202 header()->setSectionHidden( logicalIndex
, hide
);
204 emit
columnVisibilityChanged( logicalIndex
);
207 bool TreeWidget::isColumnHidden( int logicalIndex
) const
209 return header()->isSectionHidden( logicalIndex
);
212 bool TreeWidget::fillHeaderContextMenu( KMenu
* menu
, const QPoint
& )
214 if ( !menu
|| !mEnableManualColumnHiding
)
217 menu
->addTitle( i18n("View Columns") );
219 QTreeWidgetItem
* hitem
= headerItem();
221 return false; // oops..
223 // Dynamically build the menu and check the items for visible columns
224 int cc
= hitem
->columnCount();
228 for ( int i
= 1 ; i
< cc
; i
++ )
230 QAction
* act
= menu
->addAction( hitem
->text( i
) );
231 act
->setCheckable( true );
232 if ( !header()->isSectionHidden( i
) )
233 act
->setChecked( true );
234 act
->setData( QVariant( i
) );
237 act
, SIGNAL(triggered(bool)),
238 this, SLOT(slotToggleColumnActionTriggered(bool)) );
244 void TreeWidget::toggleColumn( int logicalIndex
)
246 setColumnHidden( logicalIndex
, !header()->isSectionHidden( logicalIndex
) );
250 void TreeWidget::slotToggleColumnActionTriggered( bool )
252 QAction
*act
= dynamic_cast< QAction
* >( sender() );
256 QVariant data
= act
->data();
259 int id
= data
.toInt( &ok
);
263 if ( id
> columnCount() )
266 setColumnHidden( id
, !act
->isChecked() );
269 void TreeWidget::slotHeaderContextMenuRequested( const QPoint
&clickPoint
)
273 if ( !fillHeaderContextMenu( &menu
, clickPoint
) )
276 menu
.exec( header()->mapToGlobal( clickPoint
) );
279 int TreeWidget::addColumn( const QString
&label
, int headerAlignment
)
281 QTreeWidgetItem
* hitem
= headerItem();
284 // In fact this seems to never happen
285 hitem
= new QTreeWidgetItem( this );
286 hitem
->setText( 0, label
);
287 hitem
->setTextAlignment( 0, headerAlignment
);
288 setHeaderItem( hitem
); // will set column count to 1
292 int cc
= columnCount();
294 setColumnCount( cc
+ 1 );
295 hitem
->setText( cc
, label
);
296 hitem
->setTextAlignment( cc
, headerAlignment
);
300 bool TreeWidget::setColumnText( int columnIndex
, const QString
&label
)
302 if ( columnIndex
>= columnCount() )
304 QTreeWidgetItem
* hitem
= headerItem();
307 hitem
->setText( columnIndex
, label
);
311 QTreeWidgetItem
* TreeWidget::firstItem() const
313 if ( topLevelItemCount() < 1 )
315 return topLevelItem( 0 );
318 QTreeWidgetItem
* TreeWidget::lastItem() const
320 QTreeWidgetItem
*it
= 0;
321 int cc
= topLevelItemCount();
324 it
= topLevelItem( cc
- 1 );
326 return 0; // sanity check
327 cc
= it
->childCount();
330 it
= it
->child( cc
- 1 );
332 return 0; // aaaaaargh: something is really wrong :D
333 cc
= it
->childCount();