33 #include <config-kleopatra.h>
43 #include <kleo/stl_util.h>
44 #include <kleo/keyfilter.h>
45 #include <kleo/keyfiltermanager.h>
47 #include <gpgme++/key.h>
51 #include <KConfigGroup>
54 #include <KActionCollection>
56 #include <QGridLayout>
59 #include <QToolButton>
62 #include <QInputDialog>
69 using namespace boost;
70 using namespace GpgME;
79 Page(
const KConfigGroup & group,
QWidget * parent=0 );
82 void setTemporary(
bool temporary );
83 bool isTemporary()
const {
return m_isTemporary; }
85 void setHierarchicalView(
bool hierarchical );
86 void setStringFilter(
const QString & filter );
89 QString title()
const {
return m_title.isEmpty() && keyFilter() ? keyFilter()->name() : m_title ; }
90 void setTitle(
const QString & title );
92 QString
toolTip()
const {
return m_toolTip.isEmpty() ? title() : m_toolTip ; }
93 void setToolTip(
const QString & tip );
95 bool canBeClosed()
const {
return m_canBeClosed; }
96 bool canBeRenamed()
const {
return m_canBeRenamed; }
97 bool canChangeStringFilter()
const {
return m_canChangeStringFilter; }
98 bool canChangeKeyFilter()
const {
return m_canChangeKeyFilter && !m_isTemporary; }
99 bool canChangeHierarchical()
const {
return m_canChangeHierarchical; }
101 void saveTo( KConfigGroup & group )
const;
103 Page * clone()
const {
return new Page( *
this ); }
105 void liftAllRestrictions() {
106 m_canBeClosed = m_canBeRenamed = m_canChangeStringFilter = m_canChangeKeyFilter = m_canChangeHierarchical =
true;
110 void titleChanged(
const QString & title );
118 bool m_isTemporary : 1;
119 bool m_canBeClosed : 1;
120 bool m_canBeRenamed : 1;
121 bool m_canChangeStringFilter : 1;
122 bool m_canChangeKeyFilter : 1;
123 bool m_canChangeHierarchical : 1;
129 m_title( other.m_title ),
130 m_toolTip( other.m_toolTip ),
131 m_isTemporary( other.m_isTemporary ),
132 m_canBeClosed( other.m_canBeClosed ),
133 m_canBeRenamed( other.m_canBeRenamed ),
134 m_canChangeStringFilter( other.m_canChangeStringFilter ),
135 m_canChangeKeyFilter( other.m_canChangeKeyFilter ),
136 m_canChangeHierarchical( other.m_canChangeHierarchical )
142 :
KeyTreeView( text, KeyFilterManager::instance()->keyFilterByID( id ), proxy, parent ),
144 m_toolTip( toolTip ),
145 m_isTemporary( false ),
146 m_canBeClosed( true ),
147 m_canBeRenamed( true ),
148 m_canChangeStringFilter( true ),
149 m_canChangeKeyFilter( true ),
150 m_canChangeHierarchical( true )
165 KeyFilterManager::instance()->keyFilterByID( group.readEntry(
KEY_FILTER_ENTRY ) ),
169 m_isTemporary( false ),
170 m_canBeClosed( !group.isImmutable() ),
171 m_canBeRenamed( !group.isEntryImmutable(
TITLE_ENTRY ) ),
180 group.readEntry(
SORT_DESCENDING,
true ) ? Qt::DescendingOrder : Qt::AscendingOrder );
189 void Page::saveTo( KConfigGroup & group )
const {
193 group.writeEntry(
KEY_FILTER_ENTRY, keyFilter() ? keyFilter()->
id() : QString() );
197 group.writeEntry(
SORT_DESCENDING, sortOrder() == Qt::DescendingOrder );
200 void Page::setStringFilter(
const QString & filter ) {
201 if ( !m_canChangeStringFilter )
203 KeyTreeView::setStringFilter( filter );
207 if ( !canChangeKeyFilter() )
209 const QString oldTitle = title();
210 KeyTreeView::setKeyFilter( filter );
211 const QString newTitle = title();
212 if ( oldTitle != newTitle )
213 emit titleChanged( newTitle );
216 void Page::setTitle(
const QString & t ) {
219 if ( !m_canBeRenamed )
221 const QString oldTitle = title();
223 const QString newTitle = title();
224 if ( oldTitle != newTitle )
225 emit titleChanged( newTitle );
228 void Page::setToolTip(
const QString & tip ) {
229 if ( tip == m_toolTip )
231 if ( !m_canBeRenamed )
233 const QString oldTip =
toolTip();
235 const QString newTip =
toolTip();
236 if ( oldTip != newTip )
237 emit titleChanged( title() );
240 void Page::setHierarchicalView(
bool on ) {
241 if ( !m_canChangeHierarchical )
243 KeyTreeView::setHierarchicalView( on );
246 void Page::setTemporary(
bool on ) {
247 if ( on == m_isTemporary )
260 class TabWidget::Private {
261 friend class ::Kleo::TabWidget;
268 void slotContextMenu(
const QPoint & p ) {
269 slotContextMenu( 0, p );
271 void slotContextMenu(
QWidget * w,
const QPoint & p );
272 void currentIndexChanged(
int index );
273 void slotPageTitleChanged(
const QString & title );
275 void slotPageStringFilterChanged(
const QString & filter );
276 void slotPageHierarchyChanged(
bool on );
278 #ifndef QT_NO_INPUTDIALOG
279 void slotRenameCurrentTab() {
280 renamePage( currentPage() );
282 #endif // QT_NO_INPUTDIALOG
284 void slotDuplicateCurrentTab() {
285 duplicatePage( currentPage() );
287 void slotCloseCurrentTab() {
288 closePage( currentPage() );
290 void slotMoveCurrentTabLeft() {
291 movePageLeft( currentPage() );
293 void slotMoveCurrentTabRight() {
294 movePageRight( currentPage() );
296 void slotToggleHierarchicalView(
bool on ) {
297 toggleHierarchicalView( currentPage(), on );
299 void slotExpandAll() {
300 expandAll( currentPage() );
302 void slotCollapseAll() {
303 collapseAll( currentPage() );
306 #ifndef QT_NO_INPUTDIALOG
307 void renamePage(
Page * page );
309 void duplicatePage(
Page * page );
310 void closePage(
Page * page );
311 void movePageLeft(
Page * page );
312 void movePageRight(
Page * page );
313 void toggleHierarchicalView(
Page * page,
bool on );
314 void expandAll(
Page * page );
315 void collapseAll(
Page * page );
317 void enableDisableCurrentPageActions();
318 void enableDisablePageActions( QAction * actions[],
const Page * page );
320 Page * currentPage()
const {
321 assert( !tabWidget.currentWidget() || qobject_cast<
Page*>( tabWidget.currentWidget() ) );
322 return static_cast<Page*
>( tabWidget.currentWidget() );
324 Page * page(
unsigned int idx )
const {
325 assert( !tabWidget.widget( idx ) || qobject_cast<
Page*>( tabWidget.widget( idx ) ) );
326 return static_cast<Page*
>( tabWidget.widget( idx ) );
329 Page * senderPage()
const {
330 QObject *
const sender =
q->sender();
331 assert( !sender || qobject_cast<Page*>( sender ) );
332 return static_cast<Page*
>( sender );
335 bool isSenderCurrentPage()
const {
336 Page *
const sp = senderPage();
337 return sp && sp == currentPage();
340 QTreeView * addView(
Page * page,
Page * columnReference );
341 void setCornerAction( QAction * action, Qt::Corner corner );
346 KTabWidget tabWidget;
361 QAction * currentPageActions[NumPageActions];
362 QAction * otherPageActions[NumPageActions];
365 TabWidget::Private::Private(
TabWidget * qq )
368 hierarchicalModel( 0 ),
375 layout.setMargin( 0 );
376 layout.addWidget( &tabWidget );
378 tabWidget.setTabBarHidden(
true );
379 tabWidget.setMovable(
true );
381 connect( &tabWidget, SIGNAL(currentChanged(
int)),
382 q, SLOT(currentIndexChanged(
int)) );
383 connect( &tabWidget, SIGNAL(contextMenu(QPoint)),
384 q, SLOT(slotContextMenu(QPoint)) );
385 connect( &tabWidget, SIGNAL(contextMenu(
QWidget*,QPoint)),
386 q, SLOT(slotContextMenu(
QWidget*,QPoint)) );
389 "window_new_tab", i18n(
"New Tab"), i18n(
"Open a new tab"),
390 "tab-new-background",
q, SLOT(slotNewTab()), i18n(
"CTRL+SHIFT+N"),
false,
true
396 {
"window_rename_tab", i18n(
"Rename Tab..."), i18n(
"Rename this tab"),
397 "edit-rename",
q, SLOT(slotRenameCurrentTab()), i18n(
"CTRL+SHIFT+R"),
false,
false },
398 {
"window_duplicate_tab", i18n(
"Duplicate Tab"), i18n(
"Duplicate this tab"),
399 "tab-duplicate",
q, SLOT(slotDuplicateCurrentTab()), i18n(
"CTRL+SHIFT+D"),
false,
true },
400 {
"window_close_tab", i18n(
"Close Tab"), i18n(
"Close this tab"),
401 "tab-close",
q, SLOT(slotCloseCurrentTab()), i18n(
"CTRL+SHIFT+W"),
false,
false },
402 {
"window_move_tab_left", i18n(
"Move Tab Left"), QString(),
403 0,
q, SLOT(slotMoveCurrentTabLeft()), i18n(
"CTRL+SHIFT+LEFT"),
false,
false },
404 {
"window_move_tab_right", i18n(
"Move Tab Right"), QString(),
405 0,
q, SLOT(slotMoveCurrentTabRight()), i18n(
"CTRL+SHIFT+RIGHT"),
false,
false },
406 {
"window_view_hierarchical", i18n(
"Hierarchical Certificate List"), QString(),
407 0,
q, SLOT(slotToggleHierarchicalView(
bool)), QString(),
true,
false },
408 {
"window_expand_all", i18n(
"Expand All"), QString(),
409 0,
q, SLOT(slotExpandAll()), i18n(
"CTRL+."),
false,
false },
410 {
"window_collapse_all", i18n(
"Collapse All"), QString(),
411 0,
q, SLOT(slotCollapseAll()), i18n(
"CTRL+,"),
false,
false },
414 for (
unsigned int i = 0 ; i < NumPageActions ; ++i )
417 for (
unsigned int i = 0 ; i < NumPageActions ; ++i ) {
419 assert( QString::fromLatin1( ad.
name ).startsWith( QLatin1String(
"window_" ) ) );
420 ad.
name = ad.
name + strlen(
"window_");
427 setCornerAction( newAction, Qt::TopLeftCorner );
428 setCornerAction( currentPageActions[Close], Qt::TopRightCorner );
431 void TabWidget::Private::slotContextMenu(
QWidget * w,
const QPoint & p ) {
432 assert( !w || qobject_cast<Page*>( w ) );
433 Page *
const contextMenuPage =
static_cast<Page*
>( w );
434 const Page *
const current = currentPage();
436 QAction **
const actions = contextMenuPage == current ? currentPageActions : otherPageActions ;
438 if ( contextMenuPage != current )
439 enableDisablePageActions( actions, contextMenuPage );
442 menu.addAction( actions[Rename] );
444 menu.addAction( newAction );
445 menu.addAction( actions[Duplicate] );
447 menu.addAction( actions[MoveLeft] );
448 menu.addAction( actions[MoveRight] );
450 menu.addAction( actions[Close] );
452 const QAction *
const action = menu.exec( p );
454 if ( contextMenuPage == current || action == newAction )
457 #ifndef QT_NO_INPUTDIALOG
458 if ( action == otherPageActions[Rename] )
459 renamePage( contextMenuPage );
460 #endif // QT_NO_INPUTDIALOG
461 else if ( action == otherPageActions[Duplicate] )
462 duplicatePage( contextMenuPage );
463 else if ( action == otherPageActions[Close] )
464 closePage( contextMenuPage );
465 else if ( action == otherPageActions[MoveLeft] )
466 movePageLeft( contextMenuPage );
467 else if ( action == otherPageActions[MoveRight] )
468 movePageRight( contextMenuPage );
472 void TabWidget::Private::currentIndexChanged(
int index ) {
473 const Page *
const page = this->page( index );
474 emit
q->currentViewChanged( page ? page->view() : 0 );
476 emit
q->stringFilterChanged( page ? page->stringFilter() : QString() );
477 enableDisableCurrentPageActions();
480 void TabWidget::Private::enableDisableCurrentPageActions() {
481 const Page *
const page = currentPage();
483 emit
q->enableChangeStringFilter( page && page->canChangeStringFilter() );
484 emit
q->enableChangeKeyFilter( page && page->canChangeKeyFilter() );
486 enableDisablePageActions( currentPageActions, page );
489 void TabWidget::Private::enableDisablePageActions( QAction * actions[],
const Page * p ) {
490 actions[Rename] ->setEnabled( p && p->canBeRenamed() );
491 actions[Duplicate] ->setEnabled( p );
492 actions[Close] ->setEnabled( p && p->canBeClosed() && tabWidget.count() > 1 );
493 actions[MoveLeft] ->setEnabled( p && tabWidget.indexOf( const_cast<Page*>(p) ) != 0 );
494 actions[MoveRight] ->setEnabled( p && tabWidget.indexOf( const_cast<Page*>(p) ) != tabWidget.count()-1 );
495 actions[Hierarchical]->setEnabled( p && p->canChangeHierarchical() );
496 actions[Hierarchical]->setChecked( p && p->isHierarchicalView() );
497 actions[ExpandAll] ->setEnabled( p && p->isHierarchicalView() );
498 actions[CollapseAll] ->setEnabled( p && p->isHierarchicalView() );
500 tabWidget.setTabBarHidden( tabWidget.count() < 2 );
503 void TabWidget::Private::slotPageTitleChanged(
const QString & ) {
504 if (
Page *
const page = senderPage() ) {
505 const int idx = tabWidget.indexOf( page );
506 tabWidget.setTabText( idx, page->title() );
507 tabWidget.setTabToolTip( idx, page->toolTip() );
512 if ( isSenderCurrentPage() )
513 emit
q->keyFilterChanged( kf );
516 void TabWidget::Private::slotPageStringFilterChanged(
const QString & filter ) {
517 if ( isSenderCurrentPage() )
518 emit
q->stringFilterChanged( filter );
521 void TabWidget::Private::slotPageHierarchyChanged(
bool ) {
522 enableDisableCurrentPageActions();
525 void TabWidget::Private::slotNewTab() {
526 Page * page =
new Page( QString(), QLatin1String(
"all-certificates"), QString() );
527 addView( page, currentPage() );
528 tabWidget.setCurrentIndex( tabWidget.count()-1 );
531 #ifndef QT_NO_INPUTDIALOG
532 void TabWidget::Private::renamePage(
Page * page ) {
536 const QString text = QInputDialog::getText(
q, i18n(
"Rename Tab"), i18n(
"New tab title:"), QLineEdit::Normal, page->title(), &ok );
539 page->setTitle( text );
543 void TabWidget::Private::duplicatePage(
Page * page ) {
546 Page *
const clone = page->clone();
548 clone->liftAllRestrictions();
549 addView( clone, page );
552 void TabWidget::Private::closePage(
Page * page) {
553 if ( !page || !page->canBeClosed() || tabWidget.count() <= 1 )
555 emit
q->viewAboutToBeRemoved( page->view() );
556 tabWidget.removeTab( tabWidget.indexOf( page ) );
557 enableDisableCurrentPageActions();
560 void TabWidget::Private::movePageLeft(
Page * page ) {
563 const int idx = tabWidget.indexOf( page );
566 tabWidget.moveTab( idx, idx-1 );
567 enableDisableCurrentPageActions();
570 void TabWidget::Private::movePageRight(
Page * page ) {
573 const int idx = tabWidget.indexOf( page );
574 if ( idx < 0 || idx >= tabWidget.count()-1 )
576 tabWidget.moveTab( idx, idx+1 );
577 enableDisableCurrentPageActions();
580 void TabWidget::Private::toggleHierarchicalView(
Page * page,
bool on ) {
583 page->setHierarchicalView( on );
586 void TabWidget::Private::expandAll(
Page * page ) {
587 if ( !page || !page->view() )
589 page->view()->expandAll();
592 void TabWidget::Private::collapseAll(
Page * page ) {
593 if ( !page || !page->view() )
595 page->view()->collapseAll();
598 TabWidget::TabWidget(
QWidget * p, Qt::WindowFlags f )
599 :
QWidget( p, f ),
d( new Private( this ) )
607 if ( model ==
d->flatModel )
609 d->flatModel = model;
610 for (
unsigned int i = 0, end =
count() ; i != end ; ++i )
611 if (
Page *
const page =
d->page( i ) )
612 page->setFlatModel( model );
620 if ( model ==
d->hierarchicalModel )
622 d->hierarchicalModel = model;
623 for (
unsigned int i = 0, end =
count() ; i != end ; ++i )
624 if (
Page *
const page =
d->page( i ) )
625 page->setHierarchicalModel( model );
629 return d->hierarchicalModel;
632 void TabWidget::Private::setCornerAction( QAction * action, Qt::Corner corner ) {
635 QToolButton * b =
new QToolButton;
636 b->setDefaultAction( action );
637 tabWidget.setCornerWidget( b, corner );
641 if (
Page *
const page =
d->currentPage() )
642 page->setStringFilter( filter );
646 if (
Page *
const page =
d->currentPage() )
647 page->setKeyFilter( filter );
651 std::vector<QAbstractItemView*> result;
652 const unsigned int N =
count();
654 for (
unsigned int i = 0 ; i != N ; ++i )
655 if (
const Page *
const p =
d->page( i ) )
656 result.push_back( p->view() );
661 if (
Page *
const page =
d->currentPage() )
668 return d->tabWidget.count();
672 for (
unsigned int i = 0, end =
count() ; i != end ; ++i )
673 if (
const Page *
const p =
d->page( i ) )
674 if ( QTreeView *
const view = p->view() )
675 view->setSelectionMode( on ? QAbstractItemView::ExtendedSelection : QAbstractItemView::SingleSelection );
681 coll->addAction(
d->newAction->objectName(),
d->newAction );
682 for (
unsigned int i = 0 ; i < Private::NumPageActions ; ++i ) {
683 QAction * a =
d->currentPageActions[i];
684 coll->addAction( a->objectName(), a );
688 QAbstractItemView *
TabWidget::addView(
const QString & title,
const QString &
id,
const QString & text ) {
689 return d->addView(
new Page( title,
id, text ),
d->currentPage() );
693 return d->addView(
new Page( group ), 0 );
697 Page *
const page =
new Page( title, QString(), QString(), proxy, tabToolTip );
698 page->setTemporary(
true );
699 QAbstractItemView * v =
d->addView( page,
d->currentPage() );
700 d->tabWidget.setCurrentIndex(
d->tabWidget.count()-1 );
704 QTreeView * TabWidget::Private::addView(
Page * page,
Page * columnReference ) {
708 page->setFlatModel( flatModel );
709 page->setHierarchicalModel( hierarchicalModel );
711 connect( page, SIGNAL(titleChanged(QString)),
712 q, SLOT(slotPageTitleChanged(QString)) );
715 connect( page, SIGNAL(stringFilterChanged(QString)),
716 q, SLOT(slotPageStringFilterChanged(QString)) );
717 connect( page, SIGNAL(hierarchicalChanged(
bool)),
718 q, SLOT(slotPageHierarchyChanged(
bool)) );
720 if ( columnReference ) {
721 page->setColumnSizes( columnReference->columnSizes() );
722 page->setSortColumn( columnReference->sortColumn(), columnReference->sortOrder() );
725 QAbstractItemView *
const previous =
q->currentView();
726 const int tabIndex = tabWidget.addTab( page, page->title() );
727 tabWidget.setTabToolTip( tabIndex, page->toolTip() );
729 QAbstractItemView *
const current =
q->currentView();
730 if ( previous != current )
731 currentIndexChanged( tabWidget.currentIndex() );
732 enableDisableCurrentPageActions();
733 QTreeView * view = page->view();
734 emit
q->viewAdded( view );
739 return config ? config->groupList().filter( QRegExp( QLatin1String(
"^View #\\d+$") ) ) : QStringList() ;
748 const KConfigGroup kcg( config, group );
754 addView( QString(), QLatin1String(
"my-certificates") );
755 addView( QString(), QLatin1String(
"trusted-certificates") );
756 addView( QString(), QLatin1String(
"other-certificates") );
764 config->deleteGroup( group );
766 for (
unsigned int i = 0, end =
count() ; i != end ; ++i ) {
767 if (
const Page *
const p =
d->page( i ) ) {
768 if ( p->isTemporary() )
770 KConfigGroup group( config, QString().sprintf(
"View #%u", vg++ ) );
773 group.writeEntry(
"magic", 0xFA1AFE1U );
778 static void xconnect(
const QObject * o1,
const char *
signal,
const QObject * o2,
const char *
slot ) {
779 QObject::connect( o1, signal, o2, slot );
780 QObject::connect( o2, signal, o1, slot );
789 sb, SLOT(setChangeStringFilterEnabled(
bool)) );
791 sb, SLOT(setChangeKeyFilterEnabled(
bool)) );
794 #include "moc_tabwidget.cpp"
795 #include "tabwidget.moc"
static bool xconnect(const QObject *a, const char *signal, const QObject *b, const char *slot)
KAction * make_action_from_data(const action_data &data, QObject *parent)