From 9c7b00a35f1f206082066db165d84caffa55afac Mon Sep 17 00:00:00 2001 From: Stefan Taferner Date: Tue, 10 Jun 1997 15:59:30 +0000 Subject: [PATCH] added multi-select and drag&drop svn path=/trunk/kdenetwork/kmail/; revision=228 --- kmheaders.cpp | 97 ++++++++++++++++++++++++-- kmheaders.h | 31 ++++++--- ktablistbox.cpp | 181 +++++++++++++++++++++++++++++++++++++++++++----- ktablistbox.h | 53 +++++++++++--- 4 files changed, 321 insertions(+), 41 deletions(-) diff --git a/kmheaders.cpp b/kmheaders.cpp index f2a2f0812..f048da633 100644 --- a/kmheaders.cpp +++ b/kmheaders.cpp @@ -1,7 +1,17 @@ -#include +// $Id$ + #include "kmheaders.h" #include "mclass.h" +#include "kbusyptr.h" +#include "kmdragdata.h" +#include +#include +#define MFL_DEL 'D' +#define MFL_NEW 'N' +#define MFL_UNREAD 'U' + +extern KBusyPtr* kbp; //----------------------------------------------------------------------------- KMHeaders::KMHeaders(QWidget *parent=0, const char *name=0) : KTabListBox(parent, name) @@ -74,7 +84,7 @@ void KMHeaders::deleteMsg (int msgId) Message* msg; for (msg=getMsg(msgId); msg; msg=getMsg()) - { + { msg->del(); changeItem(msg->getFlag(), getMsgIndex, 0); } @@ -94,9 +104,27 @@ void KMHeaders::undeleteMsg (int msgId) } +//----------------------------------------------------------------------------- +void KMHeaders::toggleDeleteMsg (int msgId) +{ + Message* msg; + + if (!(msg=getMsg(msgId))) return; + + if (msg->getFlag() != MFL_DEL) deleteMsg(msgId); + else undeleteMsg(msgId); +} + + //----------------------------------------------------------------------------- void KMHeaders::forwardMsg (int msgId) { + static bool isBusy = FALSE; + + if (isBusy) kbp->idle(); + else kbp->busy(); + + isBusy = !isBusy; } @@ -121,7 +149,9 @@ void KMHeaders::moveMsgToFolder (Folder* destination, int msgId) //----------------------------------------------------------------------------- Message* KMHeaders::getMsg (int msgId) { - if (!folder) + int i, high; + + if (!folder || msgId < -2) { getMsgIndex = -1; return NULL; @@ -129,15 +159,34 @@ Message* KMHeaders::getMsg (int msgId) if (msgId >= 0) { getMsgIndex = msgId; + getMsgMulti = FALSE; return folder->getMsg(msgId+1); } if (msgId == -1) { + getMsgMulti = TRUE; getMsgIndex = currentItem(); + for (i=0,high=numRows(); i=0 ? folder->getMsg(getMsgIndex+1) : NULL); } + if (getMsgIndex < 0) return NULL; + + if (getMsgMulti) for (getMsgIndex++; getMsgIndex < numRows(); getMsgIndex++) + { + if (itemList[getMsgIndex].isMarked()) + return folder->getMsg(getMsgIndex+1); + } + getMsgIndex = -1; return NULL; } @@ -158,10 +207,11 @@ void KMHeaders::changeItem (char c, int itemIndex, int column) //----------------------------------------------------------------------------- void KMHeaders::highlightMessage(int idx, int colId) { - printf ("message %d highlighted (column %d)\n", idx, colId); + kbp->busy(); if (idx >= 0) setMsgRead(idx); - + emit messageSelected(folder->getMsg(idx+1)); + kbp->idle(); } @@ -193,6 +243,7 @@ void KMHeaders::updateMessageList(void) clear(); if (!folder) return; + kbp->busy(); setAutoUpdate(FALSE); for (i = (long)1; i <= folder->numMsg(); i++) { @@ -209,6 +260,42 @@ void KMHeaders::updateMessageList(void) } setAutoUpdate(TRUE); repaint(); + kbp->idle(); +} + + +//----------------------------------------------------------------------------- +bool KMHeaders :: prepareForDrag (int aCol, int aRow, char** data, + int* size, int* type) +{ + static KmDragData dd; + int i, from, to, high; + + high = numRows()-1; + for (i=0, from=-1; i<=high; i++) + { + if (itemList[i].isMarked()) + { + from = i; + break; + } + } + for (i=high-1, to=-1; i>=0; i--) + { + if (itemList[i].isMarked()) + { + to = i; + break; + } + } + if (from < 0 || to < 0) return FALSE; + + dd.init(folder, from, to); + *data = (char*)ⅆ + *size = sizeof(dd); + *type = DndRawData; + + return TRUE; } diff --git a/kmheaders.h b/kmheaders.h index f92d9b2c8..6b4755e3d 100644 --- a/kmheaders.h +++ b/kmheaders.h @@ -16,6 +16,12 @@ public: virtual void setFolder(Folder *); Folder* currentFolder(void) { return folder; } + virtual void changeItem (char c, int itemIndex, int column); + // Change part of the contents of a line + + // The following methods process the message in the folder with + // the given msgId, or if no msgId is given all selected + // messages are processed. virtual void setMsgUnread(int msgId=-1); virtual void setMsgRead(int msgId=-1); virtual void deleteMsg(int msgId=-1); @@ -24,31 +30,36 @@ public: virtual void replyToMsg(int msgId=-1); virtual void replyAllToMsg(int msgId=-1); virtual void moveMsgToFolder(Folder* destination, int msgId=-1); - // These methods process the message in the folder with the - // given msgId, or if no msgId is given the (all) selected - // message(s) is (are) processed. + virtual void toggleDeleteMsg(int msgId=-1); + // Delete/undelete message(s) depending on the flag of + // the first selected message. - virtual void changeItem (char c, int itemIndex, int column); - // Change part of the contents of a line + Message* getMsg (int msgId=-2); + // Returns message with given id or current message if no + // id is given. First call with msgId==-1 returns first + // selected message, subsequent calls with no argument + // return the following selected messages. + + int indexOfGetMsg (void) const { return getMsgIndex; } + // Returns index of message returned by last getMsg() call signals: virtual void messageSelected(Message *); + protected slots: void selectMessage(int msgId, int colId); void highlightMessage(int msgId, int colId); protected: - Message* getMsg (int msgId=-2); - // Returns message with given id or current message if no - // id is given. First call with msgId==-1 returns first - // selected message, subsequent calls with no argument - // return the following selected messages. + virtual bool prepareForDrag (int col, int row, char** data, int* size, + int* type); private: virtual void updateMessageList(void); Folder *folder; int getMsgIndex; + bool getMsgMulti; }; #endif diff --git a/ktablistbox.cpp b/ktablistbox.cpp index 2165f83af..7a7637417 100644 --- a/ktablistbox.cpp +++ b/ktablistbox.cpp @@ -7,11 +7,13 @@ #include #include #include +#include #define INIT_MAX_ITEMS 16 #include "ktablistbox.moc" + //============================================================================= // // C L A S S KTabListBoxItem @@ -21,6 +23,7 @@ KTabListBoxItem :: KTabListBoxItem (int aColumns) { columns = aColumns; txt = new QString[columns]; + mark = -2; } @@ -37,6 +40,12 @@ void KTabListBoxItem :: setForeground (const QColor& fg) } +void KTabListBoxItem :: setMarked (int m) +{ + mark = m; +} + + KTabListBoxItem& KTabListBoxItem :: operator= (const KTabListBoxItem& from) { int i; @@ -132,8 +141,15 @@ KTabListBox :: KTabListBox (QWidget *parent, const char *name, int columns, KTabListBoxInherited (parent, name, f), lbox(this) { const QFontMetrics* fm = &fontMetrics(); + QString f; + initMetaObject(); + f = kapp->kdedir(); + f.detach(); + f += "/lib/pics/khtmlw_dnd.xpm"; + dndDefaultPixmap.load(f.data()); + maxItems = 0; current = -1; colList = NULL; @@ -144,7 +160,6 @@ KTabListBox :: KTabListBox (QWidget *parent, const char *name, int columns, if (columns > 0) lbox.setNumCols(columns); lbox.setGeometry(0, labelHeight, width(), height()-labelHeight); - } @@ -205,22 +220,54 @@ void KTabListBox :: setCurrentItem (int idx, int colId) if (idx>=numRows()) return; + unmarkAll(); + if (idx != current) { i = current; current = idx; - updateItem(i); + updateItem(i,FALSE); } if (current >= 0) { - updateItem(current); + markItem(idx); emit highlighted(current, colId); } } +//----------------------------------------------------------------------------- +void KTabListBox :: markItem (int idx, int colId) +{ + if (itemList[idx].marked()==colId) return; + itemList[idx].setMarked(colId); + updateItem(idx,FALSE); +} + + +//----------------------------------------------------------------------------- +void KTabListBox :: unmarkItem (int idx) +{ + int mark; + + mark = itemList[idx].marked(); + itemList[idx].setMarked(-2); + if (mark>=-1) updateItem(idx); +} + + +//----------------------------------------------------------------------------- +void KTabListBox :: unmarkAll (void) +{ + int i; + + for (i=numRows()-1; i>=0; i--) + unmarkItem(i); +} + + //----------------------------------------------------------------------------- void KTabListBox :: insertItem (const char* aStr, int row) { @@ -328,7 +375,13 @@ void KTabListBox :: updateItem (int row, bool erase) //----------------------------------------------------------------------------- void KTabListBox :: clear (void) { + int i; + + for (i=numRows()-1; i>=0; i--) + itemList[i].setMarked(-2); + setNumRows(0); + lbox.setTopLeftCell(0,0); current = -1; } @@ -365,12 +418,6 @@ void KTabListBox :: resizeList (int newNumItems) } -//----------------------------------------------------------------------------- -void KTabListBox :: mouseDoubleClickEvent (QMouseEvent*) -{ -} - - //----------------------------------------------------------------------------- void KTabListBox :: resizeEvent (QResizeEvent* e) { @@ -421,15 +468,26 @@ void KTabListBox :: paintEvent (QPaintEvent* e) //----------------------------------------------------------------------------- -void KTabListBox :: mousePressEvent (QMouseEvent* e) +bool KTabListBox :: startDrag (int aCol, int aRow, const QPoint& p) { - printf ("+%d+%d\n", e->pos().x(), e->pos().y()); + int dx = -(dndDefaultPixmap.width() >> 1); + int dy = -(dndDefaultPixmap.height() >> 1); + KDNDIcon* icon = new KDNDIcon(dndDefaultPixmap, p.x()+dx, p.y()+dy); + int size, type; + char* data; + + if (!prepareForDrag(aCol,aRow, &data, &size, &type)) return FALSE; + + KTabListBoxInherited::startDrag(icon, data, size, type, dx, dy); + return TRUE; } //----------------------------------------------------------------------------- -void KTabListBox :: mouseReleaseEvent (QMouseEvent*) +bool KTabListBox :: prepareForDrag (int aCol, int aRow, char** data, + int* size, int* type) { + return FALSE; } @@ -443,6 +501,7 @@ void KTabListBox :: horSbValue (int val) //----------------------------------------------------------------------------- void KTabListBox :: horSbSlidingDone () { + printf ("sliding done\n"); } @@ -453,6 +512,13 @@ void KTabListBox :: horSbSlidingDone () // C L A S S KTabListBoxTable // //============================================================================= + +QPoint KTabListBoxTable::dragStartPos; +int KTabListBoxTable::dragCol = -1; +int KTabListBoxTable::dragRow = -1; +int KTabListBoxTable::selIdx = -1; + + KTabListBoxTable :: KTabListBoxTable (KTabListBox *parent): KTabListBoxTableInherited (parent) { @@ -460,6 +526,8 @@ KTabListBoxTable :: KTabListBoxTable (KTabListBox *parent): initMetaObject(); + dragging = FALSE; + setTableFlags (Tbl_autoVScrollBar|Tbl_autoHScrollBar|Tbl_smoothVScrolling| Tbl_clipCellPainting); @@ -495,16 +563,19 @@ void KTabListBoxTable :: paintCell (QPainter* p, int row, int col) QColor bg; QColorGroup g = colorGroup(); KTabListBox* owner = (KTabListBox*)parentWidget(); + KTabListBoxItem* item = owner->getItem(row); + + if (!item) return; - if (owner->current == row) + if (item->marked()==-1) { bg = g.background(); p->fillRect (0, 0, cellWidth(col), cellHeight(row), bg); } - p->setPen (owner->itemList[row].foreground()); + p->setPen (item->foreground()); p->setBackgroundColor (g.base()); - owner->colList[col].paintCell (p, owner->itemList[row].text(col)); + owner->colList[col].paintCell (p, item->text(col)); } @@ -530,17 +601,93 @@ void KTabListBoxTable :: mouseDoubleClickEvent (QMouseEvent* e) } +//----------------------------------------------------------------------------- +void KTabListBoxTable :: doItemSelection (QMouseEvent* e, int idx) +{ + KTabListBox* owner = (KTabListBox*)parentWidget(); + int i, di; + + owner->unmarkAll(); + if ((e->state()&ShiftButton)!=0 && owner->currentItem()>=0) + { + i = owner->currentItem(); + di = (i>idx ? -1 : 1); + while (1) + { + owner->markItem(i); + if (i == idx) break; + i += di; + } + } + else owner->setCurrentItem(idx); +} + + //----------------------------------------------------------------------------- void KTabListBoxTable :: mousePressEvent (QMouseEvent* e) { KTabListBox* owner = (KTabListBox*)parentWidget(); - owner->setCurrentItem (findRow(e->pos().y()), findCol(e->pos().x())); + int idx; + + // arm for possible dragging + dragStartPos = e->pos(); + dragCol = findCol(e->pos().x()); + dragRow = findRow(e->pos().y()); + + // handle item highlighting + idx = findRow(e->pos().y()); + if (idx >= 0 && owner->getItem(idx)->marked() < -1) + { + doItemSelection(e, idx); + selIdx = idx; + } + else selIdx = -1; +} + + +//----------------------------------------------------------------------------- +void KTabListBoxTable :: mouseReleaseEvent (QMouseEvent* e) +{ + KTabListBox* owner = (KTabListBox*)parentWidget(); + int idx; + + if (dragging) + { + owner->mouseReleaseEvent(e); + dragRow = dragCol = -1; + dragging = FALSE; + } + else + { + idx = findRow(e->pos().y()); + if (idx >= 0 && selIdx < 0) + doItemSelection(e, idx); + } } //----------------------------------------------------------------------------- -void KTabListBoxTable :: mouseReleaseEvent (QMouseEvent*) +void KTabListBoxTable :: mouseMoveEvent (QMouseEvent* e) { + KTabListBox* owner = (KTabListBox*)parentWidget(); + + if (dragging) + { + owner->mouseMoveEvent(e); + return; + } + + if ((e->state() & (RightButton|LeftButton|MidButton)) != 0) + { + if (dragRow >= 0 && dragCol >= 0 && + (abs(e->pos().x()-dragStartPos.x()) >= 5 || + abs(e->pos().y()-dragStartPos.y()) >= 5)) + { + // we have a liftoff ! + dragging = owner->startDrag(dragCol, dragRow, mapToGlobal(e->pos())); + return; + } + } } diff --git a/ktablistbox.h b/ktablistbox.h index bdda28ad1..9c8f1032f 100644 --- a/ktablistbox.h +++ b/ktablistbox.h @@ -9,12 +9,13 @@ #include #include #include +#include #define MAX_SEP_CHARS 16 class KTabListBoxColumn; -class KTabListBoxItem; class KTabListBoxTable; +class KTabListBoxItem; class KTabListBox; typedef QDict KTabListBoxDict; @@ -31,20 +32,27 @@ public: virtual ~KTabListBoxTable(); protected: - virtual void mouseDoubleClickEvent (QMouseEvent *); - virtual void mousePressEvent (QMouseEvent *); - virtual void mouseReleaseEvent (QMouseEvent *); + virtual void mouseDoubleClickEvent (QMouseEvent*); + virtual void mousePressEvent (QMouseEvent*); + virtual void mouseReleaseEvent (QMouseEvent*); + virtual void mouseMoveEvent (QMouseEvent*); + virtual void doItemSelection (QMouseEvent*, int idx); virtual void paintCell (QPainter*, int row, int col); virtual int cellWidth (int col); void reconnectSBSignals (void); + + static QPoint dragStartPos; + static int dragCol, dragRow; + static int selIdx; + bool dragging; }; //-------------------------------------------------- -#define KTabListBoxInherited QWidget -class KTabListBox : public QWidget +#define KTabListBoxInherited KDNDWidget +class KTabListBox : public KDNDWidget { Q_OBJECT; friend KTabListBoxTable; @@ -82,6 +90,11 @@ public: // set the current (selected) column. colId is the value that // is transfered with the selected() signal that is emited. + virtual void unmarkAll (void); + // unmark all items + virtual void markItem (int idx, int colId=-1); + virtual void unmarkItem (int idx); + int findItem (int yPos) const { return (lbox.findRow(yPos)); } int topItem (void) const { return (lbox.topCell()); } @@ -111,6 +124,12 @@ public: void repaint (void) { QWidget::repaint(); lbox.repaint(); } + bool startDrag(int col, int row, const QPoint& mousePos); + // Indicates that a drag has started with given item. + // Returns TRUE if we are dragging, FALSE if drag-start failed. + + QPixmap& dndPixmap(void) { return dndDefaultPixmap; } + signals: void highlighted (int Index, int column); // emited when the current item changes (either via setCurrentItem() @@ -128,15 +147,18 @@ protected: void updateItem (int idx, bool clear = TRUE); bool needsUpdate (int id) { return (lbox.autoUpdate() && itemVisible(id)); } + KTabListBoxItem* getItem (int idx); + virtual void resizeEvent (QResizeEvent*); virtual void paintEvent (QPaintEvent*); virtual void resizeList (int newNumItems=-1); // Resize item array. Per default enlarge it to double size - virtual void mouseDoubleClickEvent (QMouseEvent *); - virtual void mousePressEvent (QMouseEvent *); - virtual void mouseReleaseEvent (QMouseEvent *); + virtual bool prepareForDrag (int col, int row, char** data, int* size, + int* type); + // Called to set drag data, size, and type. If this method + // returns FALSE then no drag occurs. KTabListBoxColumn* colList; KTabListBoxItem* itemList; @@ -146,6 +168,7 @@ protected: KTabListBoxDict pixDict; KTabListBoxTable lbox; int labelHeight; + QPixmap dndDefaultPixmap; private: // Disabled copy constructor and operator= KTabListBox (const KTabListBox &) {} @@ -167,10 +190,15 @@ public: KTabListBoxItem& operator= (const KTabListBoxItem&); + int marked (void) const { return mark; } + bool isMarked (void) const { return (mark >= -1); } + virtual void setMarked (int mark); + private: QString* txt; int columns; QColor fgColor; + int mark; friend class KTabListBox; }; @@ -201,4 +229,11 @@ protected: KTabListBox* parent; }; + + +inline KTabListBoxItem* KTabListBox :: getItem (int idx) +{ + return ((idx>=0 && idx