You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1273 lines
37 KiB
1273 lines
37 KiB
// kmfoldertree.cpp |
|
#include <qdragobject.h> |
|
#include <qheader.h> |
|
#include <qbitmap.h> |
|
#include <unistd.h> |
|
#include <assert.h> |
|
#include <kapp.h> |
|
#include <kconfig.h> |
|
#include <ksimpleconfig.h> |
|
#include <qpixmap.h> |
|
#include <kiconloader.h> |
|
#include <qtimer.h> |
|
#include <qpopupmenu.h> |
|
#include <klocale.h> |
|
#include <kglobal.h> |
|
#include <kstddirs.h> |
|
#include <kglobalsettings.h> |
|
#include <kmessagebox.h> |
|
|
|
#include <kdebug.h> |
|
|
|
#include "kmglobal.h" |
|
#include "kmdragdata.h" |
|
#include "kmfoldermgr.h" |
|
#include "kmfolderdir.h" |
|
#include "kmfolder.h" |
|
#include "kmfoldertree.h" |
|
#include "kmfolderdia.h" |
|
#include "kmkernel.h" |
|
#include "kmcomposewin.h" |
|
#include "kmacctmgr.h" |
|
#include "kmaccount.h" |
|
#include "kmacctimap.h" |
|
|
|
QPixmap* KMFolderTree::pixDir = 0; |
|
QPixmap* KMFolderTree::pixNode = 0; |
|
QPixmap* KMFolderTree::pixPlain = 0; |
|
QPixmap* KMFolderTree::pixFld = 0; |
|
QPixmap* KMFolderTree::pixFull = 0; |
|
QPixmap* KMFolderTree::pixIn = 0; |
|
QPixmap* KMFolderTree::pixOut = 0; |
|
QPixmap* KMFolderTree::pixTr = 0; |
|
QPixmap* KMFolderTree::pixSent = 0; |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
KMFolderTreeItem::~KMFolderTreeItem() |
|
{ |
|
if (folder && folder->account()) |
|
{ |
|
folder->account()->killJobsForItem(this); |
|
folder->remove(); |
|
delete folder; |
|
} |
|
} |
|
|
|
|
|
// Begin this code may be relicensed by Troll Tech |
|
|
|
void KMFolderTreeItem::paintCell( QPainter * p, const QColorGroup & cg, |
|
int column, int width, int align ) |
|
{ |
|
if ( !p ) |
|
return; |
|
|
|
QListView *lv = listView(); |
|
int r = lv ? lv->itemMargin() : 1; |
|
const QPixmap *icon = pixmap( column ); |
|
int marg = lv ? lv->itemMargin() : 1; |
|
|
|
if (!mPaintInfo->pixmapOn) |
|
p->fillRect( 0, 0, width, height(), cg.base() ); |
|
|
|
if ( isSelected() && |
|
(column==0 || listView()->allColumnsShowFocus()) ) { |
|
p->fillRect( r - marg, 0, width - r + marg, height(), |
|
cg.brush( QColorGroup::Highlight ) ); |
|
p->setPen( cg.highlightedText() ); |
|
} else { |
|
p->setPen( mPaintInfo->colFore ); |
|
} |
|
|
|
if ( icon ) { |
|
p->drawPixmap( r, (height()-icon->height())/2, *icon ); |
|
r += icon->width() + listView()->itemMargin(); |
|
} |
|
|
|
QString t = text( column ); |
|
if ( !t.isEmpty() ) { |
|
if( folder && (folder->countUnreadRecursive() > 0) ) { |
|
QFont f = p->font(); |
|
f.setWeight(QFont::Bold); |
|
p->setFont(f); |
|
} |
|
QRect br; |
|
p->drawText( r, 0, width-marg-r, height(), |
|
align | AlignVCenter, t, -1, &br ); |
|
if (!isSelected()) |
|
p->setPen( mPaintInfo->colUnread ); |
|
if (column == 0) |
|
p->drawText( br.right(), 0, width-marg-br.right(), height(), |
|
align | AlignVCenter, unread ); |
|
|
|
} |
|
} |
|
// End this code may be relicensed by Troll Tech |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Make sure system folders come first when sorting |
|
// (or last when sorting in descending order) |
|
QString KMFolderTreeItem::key( int, bool ) const |
|
{ |
|
if (folder->label() == i18n("inbox")) |
|
return "\t0"; |
|
else if (folder->label() == i18n("outbox")) |
|
return "\t1"; |
|
else if (folder->label() == i18n("sent-mail")) |
|
return "\t2"; |
|
else if (folder->label() == i18n("trash")) |
|
return "\t3"; |
|
else if (folder->label() == i18n("drafts")) |
|
return "\t4"; |
|
else if (folder->account()) |
|
return "\t5" + folder->label(); |
|
return text(0).lower(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
void KMFolderTree::addImapChildFolder(KMFolderTreeItem *item, |
|
const QString& name, const QString& url, const QString& mimeType, |
|
bool noPrefix) |
|
{ |
|
KMFolderTreeItem *fti = new KMFolderTreeItem( item, |
|
new KMFolder(item->folder->createChildFolder(), name), &mPaintInfo ); |
|
if (fti->folder->create()) |
|
{ |
|
fti->folder->remove(); |
|
fti->folder->create(); |
|
} |
|
fti->folder->close(); |
|
fti->folder->setAccount(item->folder->account()); |
|
fti->folder->setImapPath( url ); |
|
if ((noPrefix || item->folder->imapPath() == "/") && name == "INBOX") |
|
{ |
|
fti->folder->setLabel(i18n("inbox")); |
|
fti->folder->setSystemFolder( TRUE ); |
|
fti->setText(0, i18n("inbox")); |
|
fti->setPixmap( 0, *pixIn ); |
|
} else { |
|
fti->setText(0, name); |
|
fti->folder->setLabel(name); |
|
} |
|
if (mimeType == "message/directory" || mimeType == "inode/directory") |
|
{ |
|
fti->setExpandable( TRUE ); |
|
if (mimeType == "inode/directory") fti->folder->setDir( TRUE ); |
|
if (readIsListViewItemOpen( fti )) setOpen( fti, TRUE ); |
|
slotFolderExpanded( fti ); |
|
} |
|
|
|
connect(fti->folder,SIGNAL(numUnreadMsgsChanged(KMFolder*)), |
|
SLOT(refresh(KMFolder*))); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void KMFolderTree::drawContentsOffset( QPainter * p, int ox, int oy, |
|
int cx, int cy, int cw, int ch ) |
|
{ |
|
int c = 0; |
|
if (mPaintInfo.pixmapOn) |
|
paintEmptyArea( p, QRect( c - ox, cy - oy, cx + cw - c, ch ) ); |
|
|
|
QListView::drawContentsOffset( p, ox, oy, cx, cy, cw, ch ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
KMFolderTree::KMFolderTree(QWidget *parent,const char *name) |
|
: QListView( parent, name ), mList() |
|
{ |
|
static bool pixmapsLoaded = FALSE; |
|
oldSelected = 0; |
|
oldCurrent = 0; |
|
mLastItem = NULL; |
|
|
|
initMetaObject(); |
|
|
|
// Espen 2000-05-14: Getting rid of thick ugly frames |
|
setLineWidth(0); |
|
|
|
mUpdateTimer = NULL; |
|
setSelectionMode( Extended ); |
|
|
|
connect(this, SIGNAL(currentChanged(QListViewItem*)), |
|
this, SLOT(doFolderSelected(QListViewItem*))); |
|
connect(kernel->folderMgr(), SIGNAL(changed()), |
|
this, SLOT(doFolderListChanged())); |
|
|
|
readConfig(); |
|
|
|
addColumn( i18n("Folders"), 400 ); |
|
setShowSortIndicator(TRUE); |
|
|
|
if (!pixmapsLoaded) |
|
{ |
|
pixmapsLoaded = TRUE; |
|
|
|
pixDir = new QPixmap( UserIcon("closed")); |
|
pixNode = new QPixmap( UserIcon("green-bullet")); |
|
pixPlain = new QPixmap( SmallIcon("folder")); |
|
pixFld = new QPixmap( SmallIcon("folder")); |
|
pixFull = new QPixmap( SmallIcon("folder_open")); |
|
pixIn = new QPixmap( UserIcon("kmfldin")); |
|
pixOut = new QPixmap( UserIcon("kmfldout")); |
|
pixSent = new QPixmap( UserIcon("kmfldsent")); |
|
pixTr = new QPixmap( SmallIcon("trashcan_empty")); |
|
} |
|
setUpdatesEnabled(TRUE); |
|
reload(); |
|
cleanupConfigFile(); |
|
|
|
setAcceptDrops( TRUE ); |
|
viewport()->setAcceptDrops( TRUE ); |
|
|
|
// Drag and drop hover opening and autoscrolling support |
|
connect( &autoopen_timer, SIGNAL( timeout() ), |
|
this, SLOT( openFolder() ) ); |
|
|
|
connect( &autoscroll_timer, SIGNAL( timeout() ), |
|
this, SLOT( autoScroll() ) ); |
|
|
|
connect( this, SIGNAL( rightButtonPressed( QListViewItem*, const QPoint &, int)), |
|
this, SLOT( rightButtonPressed( QListViewItem*, const QPoint &, int))); |
|
|
|
connect( this, SIGNAL( mouseButtonPressed( int, QListViewItem*, const QPoint &, int)), |
|
this, SLOT( mouseButtonPressed( int, QListViewItem*, const QPoint &, int))); |
|
connect( this, SIGNAL( expanded( QListViewItem* ) ), |
|
this, SLOT( slotFolderExpanded( QListViewItem* ) ) ); |
|
connect( this, SIGNAL( collapsed( QListViewItem* ) ), |
|
this, SLOT( slotFolderCollapsed( QListViewItem* ) ) ); |
|
} |
|
|
|
bool KMFolderTree::event(QEvent *e) |
|
{ |
|
if (e->type() == QEvent::ApplicationPaletteChange) |
|
{ |
|
readColorConfig(); |
|
return true; |
|
} |
|
return QListView::event(e); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void KMFolderTree::createFolderList(QStringList *str, |
|
QValueList<QGuardedPtr<KMFolder> > *folders) |
|
{ |
|
QListViewItemIterator it( this ); |
|
KMFolderTreeItem *fti, *fti2; |
|
QString prefix; |
|
while (it.current()) |
|
{ |
|
fti = static_cast<KMFolderTreeItem*>(it.current()); |
|
if (fti && fti->folder) |
|
{ |
|
fti2 = static_cast<KMFolderTreeItem*>(fti->parent()); |
|
prefix = ""; |
|
while (fti2 && fti2->parent()) |
|
{ |
|
fti2 = static_cast<KMFolderTreeItem*>(fti2->parent()); |
|
prefix += " "; |
|
} |
|
str->append(prefix + fti->text(0)); |
|
if (fti->folder->isDir()) folders->append(NULL); |
|
else folders->append(fti->folder); |
|
} |
|
++it; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void KMFolderTree::createImapFolderList(KMAcctImap *account, QStringList *names, |
|
QStringList *urls, QStringList *mimeTypes) |
|
{ |
|
QListViewItemIterator it( this ); |
|
KMFolderTreeItem *fti; |
|
while (it.current()) |
|
{ |
|
fti = static_cast<KMFolderTreeItem*>(it.current()); |
|
if (fti && fti->folder && fti->folder->account() == account) |
|
{ |
|
names->append(fti->text(0)); |
|
urls->append(fti->folder->imapPath()); |
|
mimeTypes->append((fti->folder->isDir()) ? "inode/directory" : |
|
(fti->isExpandable()) ? "message/directory" : "message/digest"); |
|
} |
|
++it; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void KMFolderTree::readColorConfig (void) |
|
{ |
|
KConfig* conf = kapp->config(); |
|
// Custom/System color support |
|
conf->setGroup("Reader"); |
|
QColor c1=QColor(kapp->palette().normal().text()); |
|
QColor c2=QColor("blue"); |
|
QColor c4=QColor(kapp->palette().normal().base()); |
|
|
|
if (!conf->readBoolEntry("defaultColors",TRUE)) { |
|
mPaintInfo.colFore = conf->readColorEntry("ForegroundColor",&c1); |
|
mPaintInfo.colUnread = conf->readColorEntry("UnreadMessage",&c2); |
|
mPaintInfo.colBack = conf->readColorEntry("BackgroundColor",&c4); |
|
} |
|
else { |
|
mPaintInfo.colFore = c1; |
|
mPaintInfo.colUnread = c2; |
|
mPaintInfo.colBack = c4; |
|
} |
|
QPalette newPal = kapp->palette(); |
|
newPal.setColor( QColorGroup::Base, mPaintInfo.colBack ); |
|
newPal.setColor( QColorGroup::Text, mPaintInfo.colFore ); |
|
setPalette( newPal ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void KMFolderTree::readConfig (void) |
|
{ |
|
KConfig* conf = kapp->config(); |
|
QString fntStr; |
|
|
|
// Backing pixmap support |
|
conf->setGroup("Pixmaps"); |
|
QString pixmapFile = conf->readEntry("FolderTree",""); |
|
mPaintInfo.pixmapOn = FALSE; |
|
if (pixmapFile != "") { |
|
mPaintInfo.pixmapOn = TRUE; |
|
mPaintInfo.pixmap = QPixmap( pixmapFile ); |
|
} |
|
|
|
readColorConfig(); |
|
|
|
// Custom/Ssystem font support |
|
conf->setGroup("Fonts"); |
|
if (!conf->readBoolEntry("defaultFonts",TRUE)) { |
|
QFont folderFont = QFont("helvetica"); |
|
setFont(conf->readFontEntry("folder-font", &folderFont)); |
|
} |
|
else |
|
setFont(KGlobalSettings::generalFont()); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
KMFolderTree::~KMFolderTree() |
|
{ |
|
disconnect(kernel->folderMgr(), SIGNAL(changed()), this, SLOT(doFolderListChanged())); |
|
delete mUpdateTimer; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Updates the count of unread messages (count of unread messages |
|
// is now cached in KMails config file) |
|
void KMFolderTree::updateUnreadAll() |
|
{ |
|
bool upd = isUpdatesEnabled(); |
|
setUpdatesEnabled(FALSE); |
|
|
|
KMFolderDir* fdir; |
|
KMFolderNode* folderNode; |
|
KMFolder* folder; |
|
|
|
fdir = &kernel->folderMgr()->dir(); |
|
for (folderNode = fdir->first(); |
|
folderNode != NULL; |
|
folderNode =fdir->next()) |
|
{ |
|
if (!folderNode->isDir()) { |
|
folder = static_cast<KMFolder*>(folderNode); |
|
|
|
folder->open(); |
|
folder->countUnread(); |
|
folder->close(); |
|
} |
|
} |
|
|
|
setUpdatesEnabled(upd); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Draw empty area of list view with support for a backing pixmap |
|
void KMFolderTree::paintEmptyArea( QPainter * p, const QRect & rect ) |
|
{ |
|
if (mPaintInfo.pixmapOn) |
|
p->drawTiledPixmap( rect.left(), rect.top(), rect.width(), rect.height(), |
|
mPaintInfo.pixmap, |
|
rect.left() + contentsX(), |
|
rect.top() + contentsY() ); |
|
else |
|
p->fillRect( rect, colorGroup().base() ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Save the configuration file |
|
void KMFolderTree::writeConfig() |
|
{ |
|
QListViewItemIterator it( this ); |
|
while (it.current()) { |
|
KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current()); |
|
if (fti) |
|
writeIsListViewItemOpen(fti); |
|
++it; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Reload the tree of items in the list view |
|
void KMFolderTree::reload(void) |
|
{ |
|
KMFolderDir* fdir; |
|
QString str; |
|
|
|
writeConfig(); |
|
|
|
KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(currentItem()); |
|
if (fti && fti->folder && fti->folder->account()) |
|
doFolderSelected(0); |
|
mLastItem = NULL; |
|
QListViewItemIterator it( this ); |
|
while (it.current()) { |
|
fti = static_cast<KMFolderTreeItem*>(it.current()); |
|
if (fti && fti->folder) |
|
disconnect(fti->folder,SIGNAL(numUnreadMsgsChanged(KMFolder*)), |
|
this,SLOT(refresh(KMFolder*))); |
|
++it; |
|
} |
|
clear(); |
|
|
|
// We need our own root so that we can make it a KMFolderTreeItem |
|
// and use our custom paintBranches |
|
root = new KMFolderTreeItem( this, &mPaintInfo ); |
|
root->setOpen( TRUE ); |
|
|
|
fdir = &kernel->folderMgr()->dir(); |
|
addDirectory(fdir, root); |
|
|
|
for( KMAccount *a = kernel->acctMgr()->first(); a!=0; |
|
a = kernel->acctMgr()->next() ) |
|
if (a->type() == QString("imap")) |
|
{ |
|
KMFolderTreeItem* fti = new KMFolderTreeItem( root, |
|
new KMFolder(new KMFolderRootDir(locateLocal("tmp","")), a->name() |
|
+ ".imap"), &mPaintInfo ); |
|
fti->folder->create(); |
|
fti->folder->close(); |
|
fti->setText(0,a->name()); |
|
fti->setExpandable( TRUE ); |
|
fti->folder->setDir( TRUE ); |
|
fti->folder->setAccount( static_cast<KMAcctImap*>(a) ); |
|
fti->folder->setImapPath( static_cast<KMAcctImap*>(a)->prefix() ); |
|
if (readIsListViewItemOpen( fti )) |
|
{ |
|
setOpen( fti, TRUE ); // Does only emit a signal, when visible |
|
slotFolderExpanded( fti ); |
|
} |
|
} |
|
|
|
QListViewItemIterator jt( this ); |
|
while (jt.current()) { |
|
KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(jt.current()); |
|
if (fti && fti->folder) |
|
connect(fti->folder,SIGNAL(numUnreadMsgsChanged(KMFolder*)), |
|
this,SLOT(refresh(KMFolder*))); |
|
++jt; |
|
} |
|
refresh(0); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Recursively add a directory of folders to the tree of folders |
|
void KMFolderTree::addDirectory( KMFolderDir *fdir, QListViewItem* parent ) |
|
{ |
|
KMFolderNode *folderNode; |
|
KMFolder* folder; |
|
KMFolderTreeItem* fti; |
|
|
|
for (folderNode = fdir->first(); |
|
folderNode != NULL; |
|
folderNode = fdir->next()) |
|
if (!folderNode->isDir()) { |
|
folder = static_cast<KMFolder*>(folderNode); |
|
ASSERT(parent); |
|
fti = new KMFolderTreeItem( parent, folder, &mPaintInfo ); |
|
|
|
if (folder->label() == i18n("inbox")) |
|
fti->setPixmap( 0, *pixIn ); |
|
else if (folder->label() == i18n("outbox")) |
|
fti->setPixmap( 0, *pixOut ); |
|
else if (folder->label() == i18n("sent-mail")) |
|
fti->setPixmap( 0, *pixSent ); |
|
else if (folder->label() == i18n("trash")) |
|
fti->setPixmap( 0, *pixTr ); |
|
else |
|
fti->setPixmap( 0, *pixPlain ); |
|
|
|
if (fti->folder && fti->folder->child()) |
|
addDirectory( fti->folder->child(), fti ); |
|
fti->setOpen( readIsListViewItemOpen(fti)); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Initiate a delayed refresh of the count of unread messages |
|
// Not really need anymore as count is cached in config file. But causes |
|
// a nice blink in the foldertree, that indicates kmail did something |
|
// when the user manually checks for mail and none was found. |
|
void KMFolderTree::refresh(KMFolder* ) |
|
{ |
|
if (!mUpdateTimer) |
|
{ |
|
mUpdateTimer = new QTimer(this); |
|
connect(mUpdateTimer, SIGNAL(timeout()), this, SLOT(delayedUpdate())); |
|
} |
|
mUpdateTimer->changeInterval(200); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Updates the pixmap and extendedLabel information for items |
|
void KMFolderTree::delayedUpdate() |
|
{ |
|
QString str; |
|
bool upd = isUpdatesEnabled(); |
|
setUpdatesEnabled(FALSE); |
|
|
|
QListViewItemIterator it( this ); |
|
while (it.current()) { |
|
bool repaintRequired = false; |
|
KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current()); |
|
if (!fti || !fti->folder) { |
|
++it; |
|
continue; |
|
} |
|
|
|
QString extendedName; |
|
if (fti->folder->countUnread() > 0) { |
|
QString num; |
|
num.setNum(fti->folder->countUnread()); |
|
extendedName = " (" + num + ")"; |
|
if (!fti->folder->isSystemFolder()) |
|
fti->setPixmap( 0, *pixFull ); |
|
} |
|
else { |
|
extendedName = ""; |
|
if (!fti->folder->isSystemFolder()) |
|
fti->setPixmap( 0, *pixPlain ); |
|
} |
|
|
|
if (extendedName != fti->unread) { |
|
repaintRequired = true; |
|
fti->unread = extendedName; |
|
} |
|
|
|
if (upd && repaintRequired) |
|
for (QListViewItem *p = fti; p; p = p->parent()) p->repaint(); |
|
++it; |
|
} |
|
setUpdatesEnabled(upd); |
|
mUpdateTimer->stop(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Folders have been added/deleted update the tree of folders |
|
void KMFolderTree::doFolderListChanged() |
|
{ |
|
KMFolderTreeItem* fti = static_cast< KMFolderTreeItem* >(currentItem()); |
|
if (!fti || !fti->folder) |
|
return; |
|
KMFolder* folder = fti->folder; |
|
reload(); |
|
QListViewItem *qlvi = indexOfFolder(folder); |
|
if (qlvi) { |
|
setCurrentItem( qlvi ); |
|
setSelected( qlvi, TRUE ); |
|
} |
|
} |
|
|
|
void KMFolderTree::setSelected( QListViewItem *i, bool select ) |
|
{ |
|
clearSelection(); |
|
QListView::setSelected( i, select ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Methods for navigating folders with the keyboard |
|
|
|
void KMFolderTree::prepareItem( KMFolderTreeItem* fti ) |
|
{ |
|
QListViewItem *parent = fti->parent(); |
|
while (parent) { |
|
parent->setOpen( TRUE ); |
|
parent = parent->parent(); |
|
} |
|
ensureItemVisible( fti ); |
|
} |
|
|
|
void KMFolderTree::nextUnreadFolder() |
|
{ |
|
nextUnreadFolder( false ); |
|
} |
|
|
|
void KMFolderTree::nextUnreadFolder(bool confirm) |
|
{ |
|
QListViewItemIterator it( currentItem() ); |
|
|
|
while (it.current()) { |
|
++it; |
|
KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current()); |
|
if (fti && fti->folder && (fti->folder->countUnread() > 0)) { |
|
if ( confirm ) { |
|
if ( KMessageBox::questionYesNo( this, |
|
i18n( "Go to the next unread message in folder %1?" ). |
|
arg( fti->folder->label() ) , |
|
i18n( "Go to the next unread message" ) ) |
|
== KMessageBox::No ) return; |
|
} |
|
prepareItem( fti ); |
|
blockSignals( true ); |
|
doFolderSelected( fti ); |
|
blockSignals( false ); |
|
emit folderSelectedUnread( fti->folder ); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
void KMFolderTree::firstUnreadFolder(bool confirm) |
|
{ |
|
QListViewItemIterator it( firstChild() ); |
|
while (it.current()) |
|
{ |
|
++it; |
|
KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current()); |
|
if (fti && fti->folder && (fti->folder->countUnread() > 0)) { |
|
if ( confirm ) { |
|
if ( KMessageBox::questionYesNo( this, |
|
i18n( "Go to the next unread message in folder %1?" ). |
|
arg( fti->folder->label() ) , |
|
i18n( "Go to the next unread message" ) ) |
|
== KMessageBox::No ) return; |
|
} |
|
prepareItem( fti ); |
|
blockSignals( true ); |
|
doFolderSelected( fti ); |
|
blockSignals( false ); |
|
emit folderSelectedUnread( fti->folder ); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
void KMFolderTree::prevUnreadFolder() |
|
{ |
|
QListViewItemIterator it( currentItem() ); |
|
|
|
while (it.current()) { |
|
--it; |
|
KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current()); |
|
if (fti && fti->folder && (fti->folder->countUnread() > 0)) { |
|
prepareItem( fti ); |
|
doFolderSelected( fti ); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
void KMFolderTree::incCurrentFolder() |
|
{ |
|
QListViewItemIterator it( currentItem() ); |
|
++it; |
|
KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current()); |
|
if (fti && fti->folder) { |
|
prepareItem( fti ); |
|
disconnect(this,SIGNAL(currentChanged(QListViewItem*)), |
|
this,SLOT(doFolderSelected(QListViewItem*))); |
|
setFocus(); |
|
setCurrentItem( fti ); |
|
connect(this,SIGNAL(currentChanged(QListViewItem*)), |
|
this,SLOT(doFolderSelected(QListViewItem*))); |
|
} |
|
} |
|
|
|
void KMFolderTree::decCurrentFolder() |
|
{ |
|
QListViewItemIterator it( currentItem() ); |
|
--it; |
|
KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current()); |
|
if (fti && fti->folder) { |
|
prepareItem( fti ); |
|
disconnect(this,SIGNAL(currentChanged(QListViewItem*)), |
|
this,SLOT(doFolderSelected(QListViewItem*))); |
|
setFocus(); |
|
setCurrentItem( fti ); |
|
connect(this,SIGNAL(currentChanged(QListViewItem*)), |
|
this,SLOT(doFolderSelected(QListViewItem*))); |
|
} |
|
} |
|
|
|
void KMFolderTree::selectCurrentFolder() |
|
{ |
|
KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() ); |
|
if (fti && fti->folder) { |
|
prepareItem( fti ); |
|
doFolderSelected( fti ); |
|
} |
|
} |
|
|
|
KMFolder *KMFolderTree::currentFolder() const |
|
{ |
|
KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>( currentItem() ); |
|
if (fti ) |
|
return fti->folder; |
|
else |
|
return 0; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// When not dragging and dropping a change in the selected item |
|
// indicates the user has changed the active folder emit a signal |
|
// so that the header list and reader window can be udpated. |
|
void KMFolderTree::doFolderSelected( QListViewItem* qlvi ) |
|
{ |
|
KMFolderTreeItem* fti = static_cast< KMFolderTreeItem* >(qlvi); |
|
KMFolder* folder = 0; |
|
if (fti) folder = fti->folder; |
|
|
|
if (mLastItem && mLastItem != fti && mLastItem->folder |
|
&& mLastItem->folder->account()) |
|
{ |
|
mLastItem->folder->account()->killAllJobs(); |
|
} |
|
mLastItem = fti; |
|
|
|
clearSelection(); |
|
setCurrentItem( qlvi ); |
|
setSelected( qlvi, TRUE ); |
|
if (!folder || folder->isDir()) { |
|
emit folderSelected(0); // Root has been selected |
|
} |
|
else { |
|
QString extendedName; |
|
emit folderSelected(folder); |
|
if (fti->folder->account() && fti->mImapState |
|
!= KMFolderTreeItem::imapInProgress) |
|
fti->folder->account()->getFolder(fti); |
|
if (folder && (folder->countUnread() > 0) ) { |
|
QString num; |
|
num.setNum(folder->countUnread()); |
|
extendedName = " (" + num + ")"; |
|
} |
|
if (extendedName != fti->unread) { |
|
fti->unread = extendedName; |
|
fti->repaint(); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
void KMFolderTree::resizeEvent(QResizeEvent* e) |
|
{ |
|
KConfig* conf = kapp->config(); |
|
|
|
conf->setGroup("Geometry"); |
|
conf->writeEntry(name(), size().width()); |
|
|
|
KMFolderTreeInherited::resizeEvent(e); |
|
setColumnWidth( 0, visibleWidth() - 1 ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
QListViewItem* KMFolderTree::indexOfFolder(const KMFolder* folder) |
|
{ |
|
QListViewItemIterator it( this ); |
|
while (it.current()) { |
|
KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(it.current()); |
|
if (fti && fti->folder == folder) { |
|
return it.current(); |
|
} |
|
++it; |
|
} |
|
return 0; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Handle RMB press, show pop up menu |
|
void KMFolderTree::rightButtonPressed(QListViewItem *lvi, const QPoint &p, int) |
|
{ |
|
if (!lvi) |
|
return; |
|
setCurrentItem( lvi ); |
|
setSelected( lvi, TRUE ); |
|
|
|
if (!topLevelWidget()) return; // safe bet |
|
|
|
QPopupMenu *folderMenu = new QPopupMenu; |
|
KMFolderTreeItem* fti = static_cast<KMFolderTreeItem*>(lvi); |
|
|
|
if (!fti ) |
|
return; |
|
// ignore IMAP root folders |
|
if (fti && fti->folder && fti->folder->account() && fti->folder->isDir()) |
|
return; |
|
if ((!fti->folder || fti->folder->isDir())) |
|
{ |
|
folderMenu->insertItem(i18n("&Create Child Folder..."), this, |
|
SLOT(addChildFolder())); |
|
folderMenu-> insertItem(i18n("Compact All &Folders"), |
|
kernel->folderMgr(), SLOT(compactAll())); |
|
} |
|
else { |
|
if ((fti->folder == kernel->outboxFolder()) && (fti->folder->count()) ) |
|
folderMenu->insertItem(i18n("Send Queued"), topLevelWidget(), |
|
SLOT(slotSendQueued())); |
|
if (!fti->folder->isSystemFolder()) |
|
{ |
|
if (!fti->folder->account()) // protect from imap folders |
|
folderMenu->insertItem(i18n("&Create Child Folder..."), this, |
|
SLOT(addChildFolder())); |
|
folderMenu->insertItem(i18n("&Modify..."), topLevelWidget(), |
|
SLOT(slotModifyFolder())); |
|
} |
|
folderMenu->insertItem(i18n("C&ompact"), topLevelWidget(), |
|
SLOT(slotCompactFolder())); |
|
{ |
|
folderMenu->insertSeparator(); |
|
folderMenu->insertItem(i18n("&Empty"), topLevelWidget(), |
|
SLOT(slotEmptyFolder())); |
|
if ( (!fti->folder->isSystemFolder()) && (!fti->folder->account())) |
|
folderMenu->insertItem(i18n("&Remove"), topLevelWidget(), |
|
SLOT(slotRemoveFolder())); |
|
} |
|
if (fti->folder->isMailingList()) { |
|
folderMenu->insertSeparator(); |
|
folderMenu->insertItem(i18n("&Post to mailing-list"), |
|
topLevelWidget(), SLOT(slotCompose())); |
|
} |
|
} |
|
|
|
folderMenu->exec (p, 0); |
|
triggerUpdate(); |
|
delete folderMenu; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// If middle button and folder holds mailing-list, create a message to that list |
|
|
|
void KMFolderTree::mouseButtonPressed(int btn, QListViewItem *lvi, const QPoint &, int) |
|
{ |
|
// react on middle-button only |
|
if (btn != Qt::MidButton) return; |
|
|
|
// get underlying folder |
|
KMFolderTreeItem* fti = dynamic_cast<KMFolderTreeItem*>(lvi); |
|
|
|
if (!fti || !fti->folder) |
|
return; |
|
if (!fti->folder->isMailingList()) |
|
return; |
|
|
|
KMMessage *msg = new KMMessage; |
|
msg->initHeader(); |
|
msg->setTo(fti->folder->mailingListPostAddress()); |
|
KMComposeWin *win = new KMComposeWin(msg); |
|
win->show(); |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Create a child folder. |
|
// Requires creating the appropriate subdirectory and show a dialog |
|
void KMFolderTree::addChildFolder() |
|
{ |
|
KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(currentItem()); |
|
if (!fti) |
|
return; |
|
KMFolder *aFolder = fti->folder; |
|
if (fti->folder) |
|
if (!fti->folder->createChildFolder()) |
|
return; |
|
|
|
KMFolderDir *dir = &(kernel->folderMgr()->dir()); |
|
if (fti->folder) |
|
dir = fti->folder->child(); |
|
|
|
KMFolderDialog *d = |
|
new KMFolderDialog(0, dir, topLevelWidget(), i18n("Create Child Folder") ); |
|
|
|
if (d->exec()) { |
|
QListViewItem *qlvi = indexOfFolder( aFolder ); |
|
if (qlvi) { |
|
qlvi->setOpen(TRUE); |
|
setCurrentItem( qlvi ); |
|
} |
|
} |
|
// update if added to root Folder |
|
if (!fti->folder || fti->folder->isDir()) { |
|
doFolderListChanged(); |
|
reload(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns whether a folder directory should be open as specified in the |
|
// config file. The root is always open |
|
bool KMFolderTree::readIsListViewItemOpen(KMFolderTreeItem *fti) |
|
{ |
|
KConfig* config = kapp->config(); |
|
KMFolder *folder = fti->folder; |
|
if (!folder) |
|
return TRUE; |
|
config->setGroup("Folder-" + folder->idString()); |
|
|
|
return config->readBoolEntry("isOpen", false); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Saves open/closed state of a folder directory into the config file |
|
void KMFolderTree::writeIsListViewItemOpen(KMFolderTreeItem *fti) |
|
{ |
|
KConfig* config = kapp->config(); |
|
KMFolder *folder = fti->folder; |
|
if (!folder) |
|
return; |
|
config->setGroup("Folder-" + folder->idString()); |
|
config->writeEntry("isOpen", fti->isOpen()); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
void KMFolderTree::cleanupConfigFile() |
|
{ |
|
KConfig* appConfig = kapp->config(); |
|
appConfig->sync(); |
|
KSimpleConfig config(locateLocal("config","kmailrc")); |
|
QStringList existingFolders; |
|
QListViewItemIterator fldIt(this); |
|
QMap<QString,bool> folderMap; |
|
KMFolderTreeItem *fti; |
|
for (QListViewItemIterator fldIt(this); fldIt.current(); fldIt++) |
|
{ |
|
fti = static_cast<KMFolderTreeItem*>(fldIt.current()); |
|
if (fti && fti->folder) |
|
folderMap.insert(fti->folder->idString(), fti->isExpandable()); |
|
} |
|
QStringList groupList = config.groupList(); |
|
QString name, wholeName; |
|
int pos; |
|
bool original; |
|
for (QStringList::Iterator grpIt = groupList.begin(); |
|
grpIt != groupList.end(); grpIt++) |
|
{ |
|
if ((*grpIt).left(7) != "Folder-") continue; |
|
wholeName = name = (*grpIt).mid(7); |
|
original = TRUE; |
|
while ((folderMap.find(name) == folderMap.end()) || |
|
!(original || *(folderMap.find(name)))) |
|
{ |
|
if ((pos = name.findRev(".directory/")) != -1) |
|
{ |
|
name = name.left(pos); |
|
name.remove(((pos = name.findRev("/.")) == -1) ? 0 : (pos+1), 1); |
|
original = FALSE; |
|
} else { |
|
config.deleteGroup(*grpIt, TRUE); |
|
kdDebug() << "Deleting information about folder " << wholeName << endl; |
|
break; |
|
} |
|
} |
|
} |
|
config.sync(); |
|
appConfig->reparseConfiguration(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Drag and Drop handling -- based on the Troll Tech dirview example |
|
|
|
void KMFolderTree::openFolder() |
|
{ |
|
autoopen_timer.stop(); |
|
if ( dropItem && !dropItem->isOpen() ) { |
|
dropItem->setOpen( TRUE ); |
|
dropItem->repaint(); |
|
} |
|
} |
|
|
|
static const int autoopenTime = 750; |
|
|
|
void KMFolderTree::contentsDragEnterEvent( QDragEnterEvent *e ) |
|
{ |
|
if ( !KMHeaderToFolderDrag::canDecode(e) ) { |
|
e->ignore(); |
|
return; |
|
} |
|
|
|
oldCurrent = currentItem(); |
|
oldSelected = 0; |
|
QListViewItemIterator it( this ); |
|
while (it.current()) { |
|
if (it.current()->isSelected()) |
|
oldSelected = it.current(); |
|
++it; |
|
} |
|
setFocus(); |
|
|
|
QListViewItem *i = itemAt( contentsToViewport(e->pos()) ); |
|
if ( i ) { |
|
dropItem = i; |
|
autoopen_timer.start( autoopenTime ); |
|
} |
|
disconnect(this, SIGNAL(currentChanged(QListViewItem*)), |
|
this, SLOT(doFolderSelected(QListViewItem*))); |
|
} |
|
|
|
static const int autoscroll_margin = 16; |
|
static const int initialScrollTime = 30; |
|
static const int initialScrollAccel = 5; |
|
|
|
void KMFolderTree::startAutoScroll() |
|
{ |
|
if ( !autoscroll_timer.isActive() ) { |
|
autoscroll_time = initialScrollTime; |
|
autoscroll_accel = initialScrollAccel; |
|
autoscroll_timer.start( autoscroll_time ); |
|
} |
|
} |
|
|
|
void KMFolderTree::stopAutoScroll() |
|
{ |
|
autoscroll_timer.stop(); |
|
} |
|
|
|
void KMFolderTree::autoScroll() |
|
{ |
|
QPoint p = viewport()->mapFromGlobal( QCursor::pos() ); |
|
|
|
if ( autoscroll_accel-- <= 0 && autoscroll_time ) { |
|
autoscroll_accel = initialScrollAccel; |
|
autoscroll_time--; |
|
autoscroll_timer.start( autoscroll_time ); |
|
} |
|
int l = QMAX(1,(initialScrollTime-autoscroll_time)); |
|
|
|
int dx=0,dy=0; |
|
if ( p.y() < autoscroll_margin ) { |
|
dy = -l; |
|
} else if ( p.y() > visibleHeight()-autoscroll_margin ) { |
|
dy = +l; |
|
} |
|
if ( p.x() < autoscroll_margin ) { |
|
dx = -l; |
|
} else if ( p.x() > visibleWidth()-autoscroll_margin ) { |
|
dx = +l; |
|
} |
|
if ( dx || dy ) { |
|
scrollBy(dx,dy); |
|
} else { |
|
stopAutoScroll(); |
|
} |
|
} |
|
|
|
void KMFolderTree::contentsDragMoveEvent( QDragMoveEvent *e ) |
|
{ |
|
if ( !KMHeaderToFolderDrag::canDecode(e) ) { |
|
e->ignore(); |
|
return; |
|
} |
|
|
|
QPoint vp = contentsToViewport(e->pos()); |
|
QRect inside_margin(autoscroll_margin, autoscroll_margin, |
|
visibleWidth()-autoscroll_margin*2, |
|
visibleHeight()-autoscroll_margin*2); |
|
QListViewItem *i = itemAt( vp ); |
|
if ( i ) { |
|
setCurrentItem( i ); |
|
if ( !inside_margin.contains(vp) ) { |
|
startAutoScroll(); |
|
e->accept(QRect(0,0,0,0)); // Keep sending move events |
|
autoopen_timer.stop(); |
|
} else { |
|
e->accept(); |
|
if ( i != dropItem ) { |
|
autoopen_timer.stop(); |
|
dropItem = i; |
|
autoopen_timer.start( autoopenTime ); |
|
} |
|
} |
|
switch ( e->action() ) { |
|
case QDropEvent::Copy: |
|
break; |
|
case QDropEvent::Move: |
|
e->acceptAction(); |
|
break; |
|
case QDropEvent::Link: |
|
e->acceptAction(); |
|
break; |
|
default: |
|
; |
|
} |
|
} else { |
|
e->ignore(); |
|
autoopen_timer.stop(); |
|
dropItem = 0L; |
|
} |
|
} |
|
|
|
void KMFolderTree::contentsDragLeaveEvent( QDragLeaveEvent * ) |
|
{ |
|
autoopen_timer.stop(); |
|
stopAutoScroll(); |
|
dropItem = 0L; |
|
|
|
setCurrentItem( oldCurrent ); |
|
if (oldSelected) |
|
setSelected( oldSelected, TRUE ); |
|
connect(this, SIGNAL(currentChanged(QListViewItem*)), |
|
this, SLOT(doFolderSelected(QListViewItem*))); |
|
} |
|
|
|
void KMFolderTree::contentsDropEvent( QDropEvent *e ) |
|
{ |
|
autoopen_timer.stop(); |
|
stopAutoScroll(); |
|
|
|
QListViewItem *item = itemAt( contentsToViewport(e->pos()) ); |
|
if ( item ) { |
|
QString str; |
|
KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item); |
|
if (fti && (fti != oldSelected) && (fti->folder)) |
|
{ |
|
if (e->action() == QDropEvent::Copy) emit folderDropCopy(fti->folder); |
|
if (e->action() == QDropEvent::Move) emit folderDrop(fti->folder); |
|
} |
|
e->accept(); |
|
} else |
|
e->ignore(); |
|
|
|
// Begin this wasn't necessary in QT 2.0.2 |
|
dropItem = 0L; |
|
|
|
clearSelection(); |
|
setCurrentItem( oldCurrent ); |
|
if ( oldSelected ) |
|
setSelected( oldSelected, TRUE ); |
|
connect(this, SIGNAL(currentChanged(QListViewItem*)), |
|
this, SLOT(doFolderSelected(QListViewItem*))); |
|
// End this wasn't necessary in QT 2.0.2 |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Navigation/Selection support |
|
void KMFolderTree::keyPressEvent( QKeyEvent * e ) |
|
{ |
|
bool cntrl = (e->state() & ControlButton ); |
|
QListViewItem *cur = currentItem(); |
|
|
|
if (!e || !firstChild()) |
|
return; |
|
|
|
// If no current item, make some first item current when a key is pressed |
|
if (!cur) { |
|
clearSelection(); |
|
setCurrentItem( firstChild() ); |
|
return; |
|
} |
|
|
|
// Handle space key press |
|
if (cur->isSelectable() && e->ascii() == ' ' ) { |
|
clearSelection(); |
|
setSelected( cur, !cur->isSelected() ); |
|
doFolderSelected( cur ); |
|
return; |
|
} |
|
|
|
//Seems to behave sensibly even if ShiftButton is down, suprising |
|
if (cntrl) { |
|
disconnect(this,SIGNAL(currentChanged(QListViewItem*)), |
|
this,SLOT(doFolderSelected(QListViewItem*))); |
|
switch (e->key()) { |
|
case Key_Down: |
|
case Key_Up: |
|
case Key_Home: |
|
case Key_End: |
|
case Key_Next: |
|
case Key_Prior: |
|
case Key_Plus: |
|
case Key_Minus: |
|
case Key_Escape: |
|
KMFolderTreeInherited::keyPressEvent( e ); |
|
} |
|
connect(this,SIGNAL(currentChanged(QListViewItem*)), |
|
this,SLOT(doFolderSelected(QListViewItem*))); |
|
} |
|
} |
|
|
|
void KMFolderTree::contentsMousePressEvent( QMouseEvent * e ) |
|
{ |
|
int b = e->state() & !ShiftButton & !ControlButton; |
|
QMouseEvent *f = new QMouseEvent( QEvent::MouseButtonPress, |
|
e->pos(), |
|
e->globalPos(), |
|
e->button(), |
|
b ); |
|
clearSelection(); |
|
KMFolderTreeInherited::contentsMousePressEvent( f ); |
|
// Force current item to be selected for some reason in certain weird |
|
// circumstances this is not always the case |
|
|
|
if (currentItem()) |
|
setSelected( currentItem(), true ); |
|
} |
|
|
|
void KMFolderTree::contentsMouseReleaseEvent( QMouseEvent * e ) |
|
{ |
|
int b = e->state() & !ShiftButton & !ControlButton; |
|
QMouseEvent *f = new QMouseEvent( QEvent::MouseButtonRelease, |
|
e->pos(), |
|
e->globalPos(), |
|
e->button(), |
|
b ); |
|
KMFolderTreeInherited::contentsMouseReleaseEvent( f ); |
|
} |
|
|
|
void KMFolderTree::contentsMouseMoveEvent( QMouseEvent* e ) |
|
{ |
|
if (e->state() != NoButton) |
|
return; |
|
KMFolderTreeInherited::contentsMouseMoveEvent( e ); |
|
} |
|
|
|
void KMFolderTree::slotFolderExpanded( QListViewItem * item ) |
|
{ |
|
KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item); |
|
if (fti && fti->mImapState == KMFolderTreeItem::imapNoInformation |
|
&& fti->folder && fti->folder->account()) |
|
fti->folder->account()->listDirectory( fti ); |
|
} |
|
|
|
void KMFolderTree::slotFolderCollapsed( QListViewItem * item ) |
|
{ |
|
KMFolderTreeItem *fti = static_cast<KMFolderTreeItem*>(item); |
|
if (fti && fti->folder && fti->folder->account() |
|
&& fti->parent() && !fti->parent()->parent()) |
|
{ |
|
writeConfig(); |
|
QListViewItemIterator it(item); |
|
for (; it.current() != item->nextSibling(); it++) |
|
if ((it.current()) == currentItem()) { doFolderSelected(item); break; } |
|
while (fti->firstChild()) |
|
{ |
|
KMFolderTreeItem* ftic = static_cast<KMFolderTreeItem*> |
|
(fti->firstChild()); |
|
delete ftic; |
|
} |
|
fti->folder->account()->displayProgress(); |
|
fti->mImapState = KMFolderTreeItem::imapNoInformation; |
|
} |
|
} |
|
|
|
|
|
#include "kmfoldertree.moc" |
|
|
|
|