OSDN Git Service

refactoring.
[kita/kita.git] / kita / src / kitaui / tabwidgetbase.cpp
1 /***************************************************************************
2 *   Copyright (C) 2004 by Hideki Ikemoto , (c) 2004 by 421                *
3 *   ikemo@users.sourceforge.jp                                            *
4 *                                                                         *
5 *   This program is free software; you can redistribute it and/or modify  *
6 *   it under the terms of the GNU General Public License as published by  *
7 *   the Free Software Foundation; either version 2 of the License, or     *
8 *   (at your option) any later version.                                   *
9 ***************************************************************************/
10
11 /* Basic class of Tab widget, Tab bar, and Dock widget. */
12
13 #include "tabwidgetbase.h"
14
15 #include "kita_misc.h"
16 #include "parsemisc.h"
17 #include "signalcollection.h"
18 #include "datmanager.h"
19
20 #include <klibloader.h>
21 #include <kpopupmenu.h>
22 #include <kdebug.h>
23 #include <kstdaccel.h>
24 #include <kaction.h>
25 #include <klocale.h>
26 #include <kkeydialog.h>
27 #include <kparts/dockmainwindow.h>
28 #include <kparts/factory.h>
29 #include <kdeversion.h>
30 #include <kglobal.h>
31 #include <kconfig.h>
32 #include <kstandarddirs.h>
33
34 #include <qapplication.h>
35 #include <qmessagebox.h>
36 #include <qptrlist.h>
37 #include <qfontmetrics.h>
38
39
40 /*--------------------------------------------------------------*/
41
42
43 KitaTabWidgetBase::KitaTabWidgetBase( QWidget* parent, const char* name, WFlags f )
44         : KTabWidget( parent, name, f )
45 {
46     connectSignals();
47     setupActions();
48
49     /* setup part manager */
50     m_manager = new KParts::PartManager( parent, this, "KitaPartManager" );
51     m_manager->addManagedTopLevelWidget( parent );
52 }
53
54
55 KitaTabWidgetBase::~KitaTabWidgetBase()
56 {
57     /* romove parts */
58     if ( m_manager && !( m_manager->parts() ->isEmpty() ) ) {
59         KParts::Part * part;
60         while ( ( part = m_manager->parts() ->getFirst() ) != NULL ) {
61             m_manager->removePart( part );
62             removePage( part->widget() );
63             delete part;
64         }
65     }
66     if ( m_manager ) delete m_manager;
67     m_manager = NULL;
68
69     /* remove widgets which don't belong to parts */
70     QWidget* view = currentPage();
71     while ( count() > 0 && view ) {
72         removePage( view );
73         delete view;
74         view = currentPage();
75     }
76 }
77
78 /* public slot  */
79 void KitaTabWidgetBase::slotCurrentChanged( QWidget * w )
80 {
81     if ( m_manager == NULL ) return ;
82     if ( w == NULL ) return ;
83     w->setActiveWindow();
84     w->setFocus();
85
86     KParts::Part* part = findPartFromWidget( w );
87     if ( part ) {
88         m_manager->setActivePart( part );
89     }
90 }
91
92
93 /* show url with part. */ /* public slot */
94 void KitaTabWidgetBase::slotShowPart( const KURL& url, const QString& libName, const QString& mimetype )
95 {
96     if ( m_manager == NULL ) return ;
97
98     KLibFactory *factory = KLibLoader::self() ->factory( libName );
99     if ( !factory ) {
100         QMessageBox::critical( parentWidget(), i18n( " Load Error" ),
101                                QString( i18n( "can't load %1." ) ).arg( libName ) );
102         return ;
103     }
104
105     if ( factory->inherits( "KParts::Factory" ) ) {
106         KParts::Part * part
107         = static_cast< KParts::Factory* >( factory ) ->createPart( this );
108         m_manager->addPart( part );
109         addTab( part->widget(), url.url() );
110         showPage( part->widget() );
111         setTabToolTip( currentPage(), url.url() );
112
113         KParts::BrowserExtension *ext = KParts::BrowserExtension::childObject( part );
114         if ( ext ) {
115             KParts::URLArgs arg( false, 0, 0, mimetype );
116             ext->setURLArgs( arg );
117         }
118
119         static_cast<KParts::ReadOnlyPart*>( part ) ->openURL( url );
120     }
121 }
122
123
124 /* close num-th tab       */
125 /* see also customEvent   */ /* public slot */
126 void KitaTabWidgetBase::slotCloseTab( int num )
127 {
128     CloseTabEvent * e = new CloseTabEvent( num );
129     QApplication::postEvent( this, e );  // Qt will delete it when done
130 }
131
132
133 /* Calling deleteWidget in the child part will be the
134    cause of crash.  So you need to call deleteWidget
135    via custom event.                                   */ /* protected */ /* virtual */
136 void KitaTabWidgetBase::customEvent( QCustomEvent * e )
137 {
138     if ( e->type() == EVENT_CloseTab ) {
139         deleteWidget ( page( static_cast< CloseTabEvent* >( e ) ->getIndex() ) );
140     }
141 }
142
143
144 /* protected */ /* virtual */
145 void KitaTabWidgetBase::deleteWidget( QWidget* w )
146 {
147     if ( w == NULL ) return ;
148
149     removePage( w );
150     KParts::Part* part = findPartFromWidget( w );
151     if ( part ) m_manager->removePart( part );
152     delete w;
153 }
154
155
156 /* protected */
157 KParts::Part* KitaTabWidgetBase::findPartFromWidget( QWidget* w )
158 {
159     if ( w == NULL ) return NULL;
160     if ( m_manager == NULL ) return NULL;
161     if ( m_manager->parts() ->isEmpty() ) return NULL;
162
163     KParts::Part *part;
164     QPtrListIterator<KParts::Part> it( *( m_manager->parts() ) );
165     while ( ( part = ( *it ) ) != NULL ) {
166         if ( part->widget() == w ) return part;
167         ++it;
168     }
169
170     return NULL;
171 }
172
173
174 /* private */
175 void KitaTabWidgetBase::connectSignals()
176 {
177     /* connect signals */
178     Kita::SignalCollection * signalCollection = Kita::SignalCollection::getInstance();
179
180     connect( this, SIGNAL( currentChanged ( QWidget * ) ),
181              SLOT( slotCurrentChanged ( QWidget * ) ) );
182
183     connect( this, SIGNAL( openURLRequestExt( const KURL&, const QString ) ),
184              signalCollection, SIGNAL( openURLRequestExt( const KURL&, const QString ) ) );
185 }
186
187
188 /*------------------------------------*/
189 /* common tab actions */
190
191
192 /* private */
193 void KitaTabWidgetBase::setupActions()
194 {
195     actionCollection() ->setWidget( this );
196
197
198     QString str = i18n( "Configure S&hortcuts..." ) + "(" + QString( name() ) + ")";
199     new KAction( str,
200                  0,
201                  this,
202                  SLOT( slotConfigureKeys() ),
203                  actionCollection(),
204                  "tab_configkeys" );
205
206     new KAction( i18n( "Activate Next Tab" ),
207                  KStdAccel::tabNext(),
208                  this,
209                  SLOT( slotNextTab() ),
210                  actionCollection(),
211                  "tab_nexttab" );
212
213     new KAction( i18n( "Activate Previous Tab" ),
214                  KStdAccel::tabPrev(),
215                  this,
216                  SLOT( slotPrevTab() ),
217                  actionCollection(),
218                  "tab_prevtab" );
219
220     new KAction( i18n( "Close this tab" ),
221                  KStdAccel::close(),
222                  this,
223                  SLOT( slotCloseCurrentTab() ),
224                  actionCollection(),
225                  "tab_closetab" );
226
227     new KAction( i18n( "Close Other Tabs" ),
228                  0,
229                  this,
230                  SLOT( slotCloseOtherTab() ),
231                  actionCollection(),
232                  "tab_closeothertab" );
233
234     new KAction( i18n( "Close right tabs" ),
235                  0,
236                  this,
237                  SLOT( slotCloseRightTab() ),
238                  actionCollection(),
239                  "tab_closerighttab" );
240
241     new KAction( i18n( "Close left tabs" ),
242                  0,
243                  this,
244                  SLOT( slotCloseLeftTab() ),
245                  actionCollection(),
246                  "tab_closelefttab" );
247
248     new KAction( i18n( "Close all tabs" ),
249                  0,
250                  this,
251                  SLOT( slotCloseAllTab() ),
252                  actionCollection(),
253                  "tab_closealltab" );
254 }
255
256
257
258 /* public slot */
259 void KitaTabWidgetBase::slotConfigureKeys()
260 {
261     QString str = "Tab Actions (" + QString( name() ) + ")";
262     KKeyDialog dlg( TRUE, this );
263     dlg.insert( actionCollection(), str );
264     dlg.configure();
265 }
266
267
268 /* public slot */
269 void KitaTabWidgetBase::slotPrevTab()
270 {
271     int max = count();
272     int curpage = currentPageIndex();
273     if ( max <= 1 ) return ;
274
275     if ( curpage == 0 ) setCurrentPage( max - 1 );
276     else setCurrentPage( curpage - 1 );
277 }
278
279 /* public slot */
280 void KitaTabWidgetBase::slotNextTab()
281 {
282     int max = count();
283     int curpage = currentPageIndex();
284     if ( max <= 1 ) return ;
285
286     if ( curpage == max - 1 ) setCurrentPage( 0 );
287     else setCurrentPage( curpage + 1 );
288 }
289
290
291 /* see also customEvent */ /* public slot */
292 void KitaTabWidgetBase::slotCloseCurrentTab()
293 {
294     slotCloseTab( currentPageIndex() );
295 }
296
297
298 /* see also customEvent */ /* public slot */
299 void KitaTabWidgetBase::slotCloseOtherTab( int idx )
300 {
301     int max = count();
302     if ( max == 0 ) return ;
303     if ( idx == -1 ) idx = currentPageIndex();
304
305     int i = 0;
306
307     while ( i < max && i != idx ) {
308         slotCloseTab( 0 );
309         i++;
310     }
311
312     i++;
313     while ( i < max ) {
314         slotCloseTab( 1 );
315         i++;
316     }
317 }
318
319
320 /* see also customEvent */ /* public slot */
321 void KitaTabWidgetBase::slotCloseRightTab( int idx )
322 {
323     int max = count();
324     if ( max == 0 ) return ;
325     if ( idx == -1 ) idx = currentPageIndex();
326
327     int i, i2;
328
329     i = i2 = idx + 1;
330     while ( i < max ) {
331         slotCloseTab( i2 );
332         i++;
333     }
334 }
335
336
337 /* see also customEvent */ /* public slot */
338 void KitaTabWidgetBase::slotCloseLeftTab( int idx )
339 {
340     int max = count();
341     if ( max == 0 ) return ;
342     if ( idx == -1 ) idx = currentPageIndex();
343
344     int i = 0;
345
346     while ( i < max && i != idx ) {
347         slotCloseTab( 0 );
348         i++;
349     }
350 }
351
352
353 /* see also customEvent */ /* public slot */
354 void KitaTabWidgetBase::slotCloseAllTab()
355 {
356     int max = count();
357     if ( max == 0 ) return ;
358
359     int i = 0;
360
361     while ( i < max ) {
362         slotCloseTab( 0 );
363         i++;
364     }
365 }
366
367
368
369
370
371 /*--------------------------------------------------------------------------------*/
372 /*--------------------------------------------------------------------------------*/
373 /*--------------------------------------------------------------------------------*/
374
375
376
377
378
379 /*--------------------------------------------------------------------------------*/
380 /*--------------------------------------------------------------------------------*/
381 /*--------------------------------------------------------------------------------*/
382
383
384 KitaDockWidgetBase::KitaDockWidgetBase( KDockManager* dockManager,
385                                         const char* name,
386                                         const QPixmap &pixmap,
387                                         QWidget* parent,
388                                         const QString& strCaption,
389                                         const QString& strTabPageLabel,
390                                         WFlags f )
391         : KDockWidget( dockManager, name, pixmap, parent, strCaption, strTabPageLabel, f )
392 {
393     setDockSite( KDockWidget::DockNone );
394     m_docked = TRUE;
395     m_parentDock = static_cast< KParts::DockMainWindow* >( parent );
396     m_closeButtonClicked = FALSE;
397
398     /* connect signals */
399     connect( this, SIGNAL( headerCloseButtonClicked() ), SLOT( slotHeaderCloseButtonClicked() ) );
400     connect( this, SIGNAL( iMBeingClosed() ), SLOT( slotSaveDocStatus() ) );
401
402     Kita::SignalCollection* signalCollection = Kita::SignalCollection::getInstance();
403
404     /* emit when this widget is deactivated */
405     connect( this, SIGNAL( windowDeactivated() ),
406              signalCollection, SIGNAL( windowDeactivated() ) );
407
408     /* If this widget is active and receives
409        signal isKitaActive, then emit signal kitaIsActive. */
410     /* see also KitaHTMLPart::slotOnURL                    */
411     connect( signalCollection, SIGNAL( isKitaActive() ),
412              this, SLOT( slotIsKitaActive() ) );
413
414     connect( this, SIGNAL( kitaIsActive() ),
415              signalCollection, SIGNAL( kitaIsActive() ) );
416 }
417
418
419 KitaDockWidgetBase::~KitaDockWidgetBase() {}
420
421
422 /* public slot */
423 void KitaDockWidgetBase::slotShowPart( const KURL& url, const QString& libName, const QString& mimetype )
424 {
425     slotShowDock( TRUE, TRUE );
426
427     static_cast<KitaTabWidgetBase*> ( getWidget() ) ->slotShowPart( url, libName, mimetype );
428 }
429
430
431 /* see also KitaMainWindow::KitaMainWindow() */ /* public */
432 void KitaDockWidgetBase::loadSession()
433 {
434     QString cfgPath = locateLocal( "appdata", "session.conf" );
435     KConfig cfg( cfgPath );
436     m_tabbed = cfg.readBoolEntry( name() + QString( "_Tabbed" ), FALSE );
437     m_docked = cfg.readBoolEntry( name() + QString( "_Docked" ), FALSE );
438 }
439
440
441 /* see also KitaMainWindow::~KitaMainWindow() */ /* public */
442 void KitaDockWidgetBase::saveSession()
443 {
444     /* copied from slotSaveDocStatus */
445     if ( isVisible() ) {
446         m_docked = FALSE;
447         m_tabbed = FALSE;
448         if ( parent() ) {
449             m_docked = TRUE;
450             if ( parentDockTabGroup() ) m_tabbed = TRUE;
451         }
452     }
453
454     QString cfgPath = locateLocal( "appdata", "session.conf" );
455     KConfig cfg( cfgPath );
456     cfg.writeEntry( name() + QString( "_Tabbed" ), m_tabbed );
457     cfg.writeEntry( name() + QString( "_Docked" ), m_docked );
458 }
459
460
461 /* see also KitaMainWindow::resetWindows() */ /* public */
462 void KitaDockWidgetBase::setSession( bool docked, bool tabbed )
463 {
464     m_docked = docked;
465     m_tabbed = tabbed;
466 }
467
468
469 /* save the current dock status.                      */
470 /* This slot is called before this widget is closed.  */
471 /* See also slotHeaderCloseButtonClicked(),           */
472 /* slotHideDock(), and closeEvent().                  */ /* private slot */
473 void KitaDockWidgetBase::slotSaveDocStatus()
474 {
475     if ( isVisible() ) {
476         m_docked = FALSE;
477         m_tabbed = FALSE;
478         /* This widget is docked.*/
479         if ( parent() ) {
480             m_docked = TRUE;
481             if ( parentDockTabGroup() ) m_tabbed = TRUE; /* This widget is in the tab group.*/
482         }
483
484         emit checkToggleAction( FALSE ); /* to KitaMainWindow. see also KitaMainWindow::setupView() */
485     }
486 }
487
488 /* This slot is called when user clicks the close button.      */
489 /* m_closeButtonClicked is set to prevent from re-openning     */
490 /* the dock. To reset m_closeButtonClicked, call showDock      */
491 /* with force = TRUE.   See also slotShowDock() and showDock() */ /* private slot */
492 void KitaDockWidgetBase::slotHeaderCloseButtonClicked()
493 {
494     m_closeButtonClicked = TRUE;
495     slotSaveDocStatus();
496 }
497
498
499 /* show this dock widget later.                   */
500 /* Usually, call this slot instead of showDock(). */
501 /* See also showDock() and customEvent().         */ /* public slot */
502 void KitaDockWidgetBase::slotShowDock( bool activate, bool force )
503 {
504     ShowDockEvent * e = new ShowDockEvent( activate, force );
505     QApplication::postEvent( this, e );  // Qt will delete it when done
506 }
507
508
509 /* show this dock widget immediately.          */
510 /* If activate is TRUE, activate this dock.    */
511 /* If force is TRUE, show this anyway.         */
512 /* If force is FALSE and tab has no children,  */
513 /* this dock is not shown.                     */ /* public */
514 void KitaDockWidgetBase::showDock( bool activate, bool force )
515 {
516     if ( force ) m_closeButtonClicked = FALSE; /* see also slotHeaderCloseButtonClicked() */
517     if ( m_closeButtonClicked ) return ;
518
519     QWidget* wd = getWidget();
520     KitaTabWidgetBase* w = NULL;
521     if ( wd && wd->inherits( "KitaTabWidgetBase" ) ) w = static_cast<KitaTabWidgetBase*> ( wd );
522     if ( !force && w && w->count() == 0 ) return ;
523
524     if ( !isVisible() ) {
525
526         if ( m_docked ) { /* This dock was docked to the other dock. */
527
528             /* Sometimes the dock widget loses the former brother DockWidget.
529                because the brogher widget had transformed. So, find and set new brogher widget here. */
530
531             /* find new brother dock widget */
532             KDockWidget * newBrsDock = dockManager() ->getDockWidgetFromName( "Thread" );
533
534             if ( newBrsDock ) {
535
536                 if ( !m_tabbed ) { /* This dock was not tabbed */
537
538                     /* Is thread dock on the tab? */
539                     QWidget * tmpwidget = newBrsDock->parentDockTabGroup();
540                     if ( tmpwidget ) {
541                         tmpwidget = tmpwidget->parentWidget();
542                         if ( tmpwidget->inherits( "KDockWidget" ) )
543                             newBrsDock = static_cast< KDockWidget* >( tmpwidget );
544                     }
545                 }
546
547                 setFormerBrotherDockWidget( newBrsDock );
548             }
549             makeDockVisible();
550         } else show();
551     }
552
553     if ( !activate ) return ;
554
555     if ( isMinimized() ) showNormal();
556     topLevelWidget() ->raise();
557     raise();
558     setActiveWindow();
559     emit checkToggleAction( TRUE ); /* to KitaMainWindow */
560
561     /* activate child Part */
562     if ( w ) w->slotCurrentChanged( w->currentPage() );
563     else if ( wd ) {
564         wd->setActiveWindow();
565         wd->setFocus();
566     }
567 }
568
569
570 /* public slot */
571 void KitaDockWidgetBase::slotHideDock()
572 {
573     if ( isVisible() ) {
574         slotSaveDocStatus();
575         m_parentDock->makeDockInvisible( this );
576     }
577 }
578
579
580 /* public slot */
581 void KitaDockWidgetBase::slotToggleShowHide()
582 {
583     if ( !isVisible() ) slotShowDock( TRUE, TRUE );
584     else slotHideDock();
585 }
586
587
588 /* when this widget is deactivated, emit signal
589    to popup vie SignalCollection.               */  /* protected */
590 void KitaDockWidgetBase::windowActivationChange ( bool )
591 {
592     if ( !isActiveWindow() ) emit windowDeactivated();
593 }
594
595
596 /* protected */
597 void KitaDockWidgetBase::closeEvent( QCloseEvent* e )
598 {
599     slotSaveDocStatus();
600     KDockWidget::closeEvent( e );
601 }
602
603
604 /* protected */ /* virtual */
605 void KitaDockWidgetBase::customEvent( QCustomEvent * e )
606 {
607     if ( e->type() == EVENT_ShowDock ) {
608         ShowDockEvent * sde = static_cast< ShowDockEvent* >( e );
609         showDock( sde->getActivate(), sde->getForce() );
610     }
611 }
612
613
614 /* see also KitaHTMLPart::slotOnURL */  /* private slot */
615 void KitaDockWidgetBase::slotIsKitaActive()
616 {
617     if ( isActiveWindow() ) emit kitaIsActive();
618 }
619