/* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //BEGIN Includes #include "katefilelist.h" #include "katefilelist.moc" #include "katedocmanager.h" #include "kateviewmanager.h" #include "katemainwindow.h" #include <tqapplication.h> #include <tqpainter.h> #include <tqpopupmenu.h> #include <tqheader.h> #include <tqcolor.h> #include <tqcheckbox.h> #include <tqhbox.h> #include <tqlayout.h> #include <tqgroupbox.h> #include <tqlabel.h> #include <tqwhatsthis.h> #include <kiconloader.h> #include <kconfig.h> #include <klocale.h> #include <kglobalsettings.h> #include <kpassivepopup.h> #include <kdebug.h> #include <kapplication.h> #include <kstringhandler.h> #include <kcolorbutton.h> #include <kdialog.h> //END Includes //BEGIN ToolTip class ToolTip : public TQToolTip { public: ToolTip( TQWidget *parent, KateFileList *lv ) : TQToolTip( parent ), m_listView( lv ) { } virtual ~ToolTip() {}; void maybeTip( const TQPoint &pos ) { TQListViewItem *i = m_listView->itemAt( pos ); if ( ! i ) return; KateFileListItem *item = ((KateFileListItem*)i); if ( ! item ) return; tip( m_listView->itemRect( i ), m_listView->tooltip( item, 0 ) ); } private: KateFileList *m_listView; }; //END ToolTip //BEGIN KateFileList KateFileList::KateFileList (KateMainWindow *main, KateViewManager *_viewManager, TQWidget * parent, const char * name ) : KListView (parent, name) , m_sort( KateFileList::sortByID ) { m_main = main; m_tooltip = new ToolTip( viewport(), this ); // default colors m_viewShade = TQColor( 51, 204, 255 ); m_editShade = TQColor( 255, 102, 153 ); m_enableBgShading = false; setFocusPolicy ( TQ_NoFocus ); viewManager = _viewManager; header()->hide(); addColumn("Document Name"); setSelectionMode( TQListView::Single ); setSortType(KateFileList::sortByID); setShowToolTips( false ); setupActions (); connect(this,TQT_SIGNAL(moved()),this,TQT_SLOT(updateFileListLocations())); for (uint i = 0; i < KateDocManager::self()->documents(); i++) { slotDocumentCreated (KateDocManager::self()->document(i)); slotModChanged (KateDocManager::self()->document(i)); } connect(KateDocManager::self(),TQT_SIGNAL(documentCreated(Kate::Document *)), this,TQT_SLOT(slotDocumentCreated(Kate::Document *))); connect(KateDocManager::self(),TQT_SIGNAL(documentDeleted(uint)), this,TQT_SLOT(slotDocumentDeleted(uint))); // don't Honour KDE single/double click setting, this files are already open, // no need for hassle of considering double-click connect(this,TQT_SIGNAL(selectionChanged(TQListViewItem *)), this,TQT_SLOT(slotActivateView(TQListViewItem *))); connect(viewManager,TQT_SIGNAL(viewChanged()), this,TQT_SLOT(slotViewChanged())); connect(this,TQT_SIGNAL(contextMenuRequested( TQListViewItem *, const TQPoint &, int )), this,TQT_SLOT(slotMenu ( TQListViewItem *, const TQPoint &, int ))); } KateFileList::~KateFileList () { delete m_tooltip; } void KateFileList::setupActions () { windowNext = KStdAction::back(TQT_TQOBJECT(this), TQT_SLOT(slotPrevDocument()), m_main->actionCollection()); windowPrev = KStdAction::forward(TQT_TQOBJECT(this), TQT_SLOT(slotNextDocument()), m_main->actionCollection()); sortAction = new KSelectAction( i18n("Sort &By"), 0, m_main->actionCollection(), "filelist_sortby" ); listMoveFileUp = new KAction( i18n("Move File Up"), 0, m_main->actionCollection(), "filelist_move_up" ); //listMoveFileUp->setShortcut(KShortcut(CTRL + SHIFT + Key_Comma)); listMoveFileDown = new KAction( i18n("Move File Down"), 0, m_main->actionCollection(), "filelist_move_down" ); //listMoveFileDown->setShortcut(KShortcut(CTRL + SHIFT + Key_Period)); connect( listMoveFileUp, TQT_SIGNAL(activated()), TQT_TQOBJECT(this), TQT_SLOT(moveFileUp()) ); connect( listMoveFileDown, TQT_SIGNAL(activated()), TQT_TQOBJECT(this), TQT_SLOT(moveFileDown()) ); TQStringList l; l << i18n("Opening Order") << i18n("Document Name") << i18n("URL") << i18n("Manual Placement"); sortAction->setItems( l ); connect( sortAction, TQT_SIGNAL(activated(int)), TQT_TQOBJECT(this), TQT_SLOT(setSortType(int)) ); } void KateFileList::updateActions () { windowNext->setEnabled(KateDocManager::self()->documents() > 1); windowPrev->setEnabled(KateDocManager::self()->documents() > 1); } void KateFileList::keyPressEvent(TQKeyEvent *e) { if ( ( e->key() == Key_Return ) || ( e->key() == Key_Enter ) ) { e->accept(); slotActivateView( currentItem() ); } else { KListView::keyPressEvent(e); } } // Protect single mode selection: don't let them // leftclick outside items. // ### if we get to accept keyboard navigation, set focus before // returning void KateFileList::contentsMousePressEvent( TQMouseEvent *e ) { if ( ! itemAt( contentsToViewport( e->pos() ) ) ) return; KListView::contentsMousePressEvent( e ); } void KateFileList::resizeEvent( TQResizeEvent *e ) { KListView::resizeEvent( e ); // ### We may want to actually calculate the widest field, // since it's not automatically scrinked. If I add support for // tree or marks, the changes of the required width will vary // a lot with opening/closing of files and display changes for // the mark branches. int w = viewport()->width(); if ( columnWidth( 0 ) < w ) setColumnWidth( 0, w ); } void KateFileList::slotNextDocument() { if ( ! currentItem() || childCount() == 0 ) return; // ### more checking once more item types are added if ( currentItem()->nextSibling() ) viewManager->activateView( ((KateFileListItem*)currentItem()->nextSibling())->documentNumber() ); else viewManager->activateView( ((KateFileListItem *)firstChild())->documentNumber() ); } void KateFileList::slotPrevDocument() { if ( ! currentItem() || childCount() == 0 ) return; // ### more checking once more item types are added if ( currentItem()->itemAbove() ) viewManager->activateView( ((KateFileListItem*)currentItem()->itemAbove())->documentNumber() ); else viewManager->activateView( ((KateFileListItem *)lastItem())->documentNumber() ); } void KateFileList::slotDocumentCreated (Kate::Document *doc) { new KateFileListItem( this, doc/*, doc->documentNumber()*/ ); connect(doc,TQT_SIGNAL(modStateChanged(Kate::Document *)),this,TQT_SLOT(slotModChanged(Kate::Document *))); connect(doc,TQT_SIGNAL(nameChanged(Kate::Document *)),this,TQT_SLOT(slotNameChanged(Kate::Document *))); connect(doc,TQT_SIGNAL(modifiedOnDisc(Kate::Document *, bool, unsigned char)),this,TQT_SLOT(slotModifiedOnDisc(Kate::Document *, bool, unsigned char))); sort(); updateFileListLocations(); updateActions (); } void KateFileList::slotDocumentDeleted (uint documentNumber) { TQListViewItem * item = firstChild(); while( item ) { if ( ((KateFileListItem *)item)->documentNumber() == documentNumber ) { // m_viewHistory.removeRef( (KateFileListItem *)item ); // m_editHistory.removeRef( (KateFileListItem *)item ); removeItem( item ); break; } item = item->nextSibling(); } updateFileListLocations(); updateActions (); } void KateFileList::slotActivateView( TQListViewItem *item ) { if ( ! item || item->rtti() != RTTI_KateFileListItem ) return; viewManager->activateView( ((KateFileListItem *)item)->documentNumber() ); } void KateFileList::slotModChanged (Kate::Document *doc) { if (!doc) return; TQListViewItem * item = firstChild(); while( item ) { if ( ((KateFileListItem *)item)->documentNumber() == doc->documentNumber() ) break; item = item->nextSibling(); } if ( ((KateFileListItem *)item)->document()->isModified() ) { m_editHistory.removeRef( (KateFileListItem *)item ); m_editHistory.prepend( (KateFileListItem *)item ); for ( uint i=0; i < m_editHistory.count(); i++ ) { m_editHistory.at( i )->setEditHistPos( i+1 ); repaintItem( m_editHistory.at( i ) ); } } else repaintItem( item ); } void KateFileList::slotModifiedOnDisc (Kate::Document *doc, bool, unsigned char) { slotModChanged( doc ); } void KateFileList::slotNameChanged (Kate::Document *doc) { if (!doc) return; // ### using nextSibling to *only* look at toplevel items. // child items could be marks for example TQListViewItem * item = firstChild(); while( item ) { if ( ((KateFileListItem*)item)->document() == doc ) { item->setText( 0, doc->docName() ); repaintItem( item ); break; } item = item->nextSibling(); } updateSort(); } void KateFileList::slotViewChanged () { if (!viewManager->activeView()) return; Kate::View *view = viewManager->activeView(); uint dn = view->getDoc()->documentNumber(); TQListViewItem * i = firstChild(); while( i ) { if ( ((KateFileListItem *)i)->documentNumber() == dn ) { break; } i = i->nextSibling(); } if ( ! i ) return; KateFileListItem *item = (KateFileListItem*)i; setCurrentItem( item ); // ### During load of file lists, all the loaded views gets active. // Do something to avoid shading them -- maybe not creating views, just // open the documents??? // int p = 0; // if ( m_viewHistory.count() ) // { // int p = m_viewHistory.findRef( item ); // only repaint items that needs it // } m_viewHistory.removeRef( item ); m_viewHistory.prepend( item ); for ( uint i=0; i < m_viewHistory.count(); i++ ) { m_viewHistory.at( i )->setViewHistPos( i+1 ); repaintItem( m_viewHistory.at( i ) ); } updateFileListLocations(); } void KateFileList::updateFileListLocations() { TQListViewItem* item = firstChild(); int i=0; while (item) { if (m_sort == KateFileList::sortManual) { ((KateFileListItem *)item)->document()->setDocumentListPosition(i); } else { ((KateFileListItem *)item)->document()->setDocumentListPosition(-1); } item = item->itemBelow(); i++; } } void KateFileList::slotMenu ( TQListViewItem *item, const TQPoint &p, int /*col*/ ) { if (!item) return; m_clickedMenuItem = item; if (m_clickedMenuItem->itemAbove()) { listMoveFileUp->setEnabled(true); } else { listMoveFileUp->setEnabled(false); } if (m_clickedMenuItem->itemBelow()) { listMoveFileDown->setEnabled(true); } else { listMoveFileDown->setEnabled(false); } TQPopupMenu *menu = (TQPopupMenu*) ((viewManager->mainWindow())->factory()->container("filelist_popup", viewManager->mainWindow())); if (menu) { menu->exec(p); } } TQString KateFileList::tooltip( TQListViewItem *item, int ) { KateFileListItem *i = ((KateFileListItem*)item); if ( ! i ) return TQString::null; TQString str; const KateDocumentInfo *info = KateDocManager::self()->documentInfo(i->document()); if (info && info->modifiedOnDisc) { if (info->modifiedOnDiscReason == 1) str += i18n("<b>This file was changed (modified) on disk by another program.</b><br />"); else if (info->modifiedOnDiscReason == 2) str += i18n("<b>This file was changed (created) on disk by another program.</b><br />"); else if (info->modifiedOnDiscReason == 3) str += i18n("<b>This file was changed (deleted) on disk by another program.</b><br />"); } str += i->document()->url().prettyURL(); return str; } void KateFileList::setSortType (int s) { m_sort = s; if (m_sort == KateFileList::sortManual) { setSorting( -1, true ); setDragEnabled(true); setAcceptDrops(true); } else { setSorting( 0, true ); setDragEnabled(false); setAcceptDrops(false); updateSort (); } } void KateFileList::moveFileUp() { if (m_clickedMenuItem) { sortAction->setCurrentItem(KateFileList::sortManual); setSortType(KateFileList::sortManual); TQListViewItem* nitemabove = m_clickedMenuItem->itemAbove(); if (nitemabove) { nitemabove = nitemabove->itemAbove(); if (nitemabove) { m_clickedMenuItem->moveItem(nitemabove); } else { // Qt made this hard nitemabove = m_clickedMenuItem->itemAbove(); nitemabove->moveItem(m_clickedMenuItem); } } } updateFileListLocations(); } void KateFileList::moveFileDown() { if (m_clickedMenuItem) { sortAction->setCurrentItem(KateFileList::sortManual); setSortType(KateFileList::sortManual); TQListViewItem* nitemabove = m_clickedMenuItem->itemBelow(); if (nitemabove) { m_clickedMenuItem->moveItem(nitemabove); } } updateFileListLocations(); } void KateFileList::updateSort () { sort (); updateFileListLocations(); } void KateFileList::readConfig( KConfig *config, const TQString &group ) { TQString oldgroup = config->group(); config->setGroup( group ); setSortType( config->readNumEntry( "Sort Type", sortByID ) ); m_viewShade = config->readColorEntry( "View Shade", &m_viewShade ); m_editShade = config->readColorEntry( "Edit Shade", &m_editShade ); m_enableBgShading = config->readBoolEntry( "Shading Enabled", &m_enableBgShading ); sortAction->setCurrentItem( sortType() ); config->setGroup( oldgroup ); } void KateFileList::writeConfig( KConfig *config, const TQString &group ) { TQString oldgroup = config->group(); config->setGroup( group ); config->writeEntry( "Sort Type", m_sort ); config->writeEntry( "View Shade", m_viewShade ); config->writeEntry( "Edit Shade", m_editShade ); config->writeEntry( "Shading Enabled", m_enableBgShading ); config->setGroup( oldgroup ); } void KateFileList::takeItem( TQListViewItem *item ) { if ( item->rtti() == RTTI_KateFileListItem ) { m_editHistory.removeRef( (KateFileListItem*)item ); m_viewHistory.removeRef( (KateFileListItem*)item ); } TQListView::takeItem( item ); } //END KateFileList //BEGIN KateFileListItem KateFileListItem::KateFileListItem( TQListView* lv, Kate::Document *_doc ) : TQListViewItem( lv, _doc->docName() ), doc( _doc ), m_viewhistpos( 0 ), m_edithistpos( 0 ), m_docNumber( _doc->documentNumber() ) { // Move this document to the end of the list where it belongs TQListViewItem* lastitem = lv->lastItem(); if (lastitem) { moveItem(lastitem); } } KateFileListItem::~KateFileListItem() { } const TQPixmap *KateFileListItem::pixmap ( int column ) const { if ( column == 0) { static TQPixmap noPm = SmallIcon ("null"); static TQPixmap modPm = SmallIcon("modified"); static TQPixmap discPm = SmallIcon("modonhd"); static TQPixmap modmodPm = SmallIcon("modmod"); const KateDocumentInfo *info = KateDocManager::self()->documentInfo(doc); if (info && info->modifiedOnDisc) return doc->isModified() ? &modmodPm : &discPm; else return doc->isModified() ? &modPm : &noPm; } return 0; } void KateFileListItem::paintCell( TQPainter *painter, const TQColorGroup & cg, int column, int width, int align ) { KateFileList *fl = (KateFileList*)listView(); if ( ! fl ) return; if ( column == 0 ) { TQColorGroup cgNew = cg; // replace the base color with a different shading if necessary... if ( fl->shadingEnabled() && m_viewhistpos > 1 ) { TQColor b( cg.base() ); TQColor shade = fl->viewShade(); TQColor eshade = fl->editShade(); int hc = fl->histCount(); // If this file is in the edit history, blend in the eshade // color. The blend is weighted by the position in the editing history if ( fl->shadingEnabled() && m_edithistpos > 0 ) { int ec = fl->editHistCount(); int v = hc-m_viewhistpos; int e = ec-m_edithistpos+1; e = e*e; int n = QMAX(v + e, 1); shade.setRgb( ((shade.red()*v) + (eshade.red()*e))/n, ((shade.green()*v) + (eshade.green()*e))/n, ((shade.blue()*v) + (eshade.blue()*e))/n ); } // blend in the shade color. // max transperancy < .5, latest is most colored. float t = (0.5/hc)*(hc-m_viewhistpos+1); b.setRgb( (int)((b.red()*(1-t)) + (shade.red()*t)), (int)((b.green()*(1-t)) + (shade.green()*t)), (int)((b.blue()*(1-t)) + (shade.blue()*t)) ); cgNew.setColor(TQColorGroup::Base, b); } TQListViewItem::paintCell( painter, cgNew, column, width, align ); } else TQListViewItem::paintCell( painter, cg, column, width, align ); } int KateFileListItem::compare ( TQListViewItem * i, int col, bool ascending ) const { if ( i->rtti() == RTTI_KateFileListItem ) { switch( ((KateFileList*)listView())->sortType() ) { case KateFileList::sortByID: { int d = (int)doc->documentNumber() - ((KateFileListItem*)i)->documentNumber(); return ascending ? d : -d; break; } case KateFileList::sortByURL: return doc->url().prettyURL().compare( ((KateFileListItem*)i)->document()->url().prettyURL() ); break; default: return TQListViewItem::compare( i, col, ascending ); } } return 0; } //END KateFileListItem //BEGIN KFLConfigPage KFLConfigPage::KFLConfigPage( TQWidget* parent, const char *name, KateFileList *fl ) : Kate::ConfigPage( parent, name ), m_filelist( fl ), m_changed( false ) { TQVBoxLayout *lo1 = new TQVBoxLayout( this ); int spacing = KDialog::spacingHint(); lo1->setSpacing( spacing ); TQGroupBox *gb = new TQGroupBox( 1, Qt::Horizontal, i18n("Background Shading"), this ); lo1->addWidget( gb ); TQWidget *g = new TQWidget( gb ); TQGridLayout *lo = new TQGridLayout( g, 2, 2 ); lo->setSpacing( KDialog::spacingHint() ); cbEnableShading = new TQCheckBox( i18n("&Enable background shading"), g ); lo->addMultiCellWidget( cbEnableShading, 1, 1, 0, 1 ); kcbViewShade = new KColorButton( g ); lViewShade = new TQLabel( kcbViewShade, i18n("&Viewed documents' shade:"), g ); lo->addWidget( lViewShade, 2, 0 ); lo->addWidget( kcbViewShade, 2, 1 ); kcbEditShade = new KColorButton( g ); lEditShade = new TQLabel( kcbEditShade, i18n("&Modified documents' shade:"), g ); lo->addWidget( lEditShade, 3, 0 ); lo->addWidget( kcbEditShade, 3, 1 ); // sorting TQHBox *hbSorting = new TQHBox( this ); lo1->addWidget( hbSorting ); lSort = new TQLabel( i18n("&Sort by:"), hbSorting ); cmbSort = new TQComboBox( hbSorting ); lSort->setBuddy( cmbSort ); TQStringList l; l << i18n("Opening Order") << i18n("Document Name") << i18n("URL"); cmbSort->insertStringList( l ); lo1->insertStretch( -1, 10 ); TQWhatsThis::add( cbEnableShading, i18n( "When background shading is enabled, documents that have been viewed " "or edited within the current session will have a shaded background. " "The most recent documents have the strongest shade.") ); TQWhatsThis::add( kcbViewShade, i18n( "Set the color for shading viewed documents.") ); TQWhatsThis::add( kcbEditShade, i18n( "Set the color for modified documents. This color is blended into " "the color for viewed files. The most recently edited documents get " "most of this color.") ); TQWhatsThis::add( cmbSort, i18n( "Set the sorting method for the documents.") ); reload(); slotEnableChanged(); connect( cbEnableShading, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotMyChanged()) ); connect( cbEnableShading, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotEnableChanged()) ); connect( kcbViewShade, TQT_SIGNAL(changed(const TQColor&)), this, TQT_SLOT(slotMyChanged()) ); connect( kcbEditShade, TQT_SIGNAL(changed(const TQColor&)), this, TQT_SLOT(slotMyChanged()) ); connect( cmbSort, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotMyChanged()) ); } void KFLConfigPage::apply() { if ( ! m_changed ) return; m_changed = false; // Change settings in the filelist m_filelist->m_viewShade = kcbViewShade->color(); m_filelist->m_editShade = kcbEditShade->color(); m_filelist->m_enableBgShading = cbEnableShading->isChecked(); m_filelist->setSortType( cmbSort->currentItem() ); // repaint the affected items m_filelist->triggerUpdate(); } void KFLConfigPage::reload() { // read in from config file KConfig *config = kapp->config(); config->setGroup( "Filelist" ); cbEnableShading->setChecked( config->readBoolEntry("Shading Enabled", &m_filelist->m_enableBgShading ) ); kcbViewShade->setColor( config->readColorEntry("View Shade", &m_filelist->m_viewShade ) ); kcbEditShade->setColor( config->readColorEntry("Edit Shade", &m_filelist->m_editShade ) ); cmbSort->setCurrentItem( m_filelist->sortType() ); m_changed = false; } void KFLConfigPage::slotEnableChanged() { kcbViewShade->setEnabled( cbEnableShading->isChecked() ); kcbEditShade->setEnabled( cbEnableShading->isChecked() ); lViewShade->setEnabled( cbEnableShading->isChecked() ); lEditShade->setEnabled( cbEnableShading->isChecked() ); } void KFLConfigPage::slotMyChanged() { m_changed = true; slotChanged(); } //END KFLConfigPage // kate: space-indent on; indent-width 2; replace-tabs on;