linuxdcpp-team team mailing list archive
-
linuxdcpp-team team
-
Mailing list archive
-
Message #05846
[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 2994: add a virtual tree control to deal with large trees (only inserts nodes when expanding their parent)
------------------------------------------------------------
revno: 2994
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Thu 2012-07-12 22:49:11 +0200
message:
add a virtual tree control to deal with large trees (only inserts nodes when expanding their parent)
added:
dwt/include/dwt/widgets/VirtualTree.h
dwt/src/widgets/VirtualTree.cpp
modified:
changelog.txt
win32/DirectoryListingFrame.cpp
win32/DirectoryListingFrame.h
--
lp:dcplusplus
https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk
Your team Dcplusplus-team is subscribed to branch lp:dcplusplus.
To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'changelog.txt'
--- changelog.txt 2012-07-12 13:17:54 +0000
+++ changelog.txt 2012-07-12 20:49:11 +0000
@@ -26,6 +26,9 @@
* [dwt] Add a link control (poy)
* Allow Magnet links to be pasted in the "Quick connect" box (poy)
* Rise the minislot size to 512 KiB
+* More Alt+I shortcuts for list filters (emtee)
+* Increase the chat buffer limit (iceman50)
+* Eliminate GUI freezes when opening large file lists (poy)
-- 0.799 2012-05-05 --
* Add icons (iceman50)
=== added file 'dwt/include/dwt/widgets/VirtualTree.h'
--- dwt/include/dwt/widgets/VirtualTree.h 1970-01-01 00:00:00 +0000
+++ dwt/include/dwt/widgets/VirtualTree.h 2012-07-12 20:49:11 +0000
@@ -0,0 +1,134 @@
+/*
+ DC++ Widget Toolkit
+
+ Copyright (c) 2007-2012, Jacek Sieka
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the DWT nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef DWT_VIRTUALTREE_H
+#define DWT_VIRTUALTREE_H
+
+#include <list>
+
+#include <boost/optional.hpp>
+
+#include "Tree.h"
+
+namespace dwt {
+
+/** This is a tree control designed to hold a large amount of items. Instead of adding all of its
+nodes to the control, it stores them internally and only adds them when required (when expanding
+parent nodes). */
+/* Implementation: Fake HTREEITEMs are delivered to the callers of a VirtualTree. Instead of
+pointing to actual nodes of the tree control, they point to an internal structure. Tree control
+messages that depend on HTREEITEMs are captured and handled internally by the VirtualTree.
+Many implementation details are inspired by Wine (dlls/comctl32/treeview.c). */
+class VirtualTree :
+ public Tree
+{
+ typedef Tree BaseType;
+ friend class WidgetCreator<VirtualTree>;
+
+public:
+ typedef VirtualTree ThisType;
+ typedef ThisType* ObjectType;
+
+ struct Seed : public BaseType::Seed {
+ typedef ThisType WidgetType;
+
+ Seed(const BaseType::Seed& seed);
+ };
+
+ virtual bool handleMessage(const MSG& msg, LRESULT& retVal);
+
+protected:
+ explicit VirtualTree(Widget* parent);
+ virtual ~VirtualTree() { }
+
+private:
+ /* info about each item; similar to TVINSERTSTRUCT / TVITEMEX. a pointer to this structure is
+ given to callers of a VirtualTree as an HTREEITEM; they can then manipulate it as usual. */
+ struct Item : boost::noncopyable {
+ HTREEITEM handle; /* the handle in the actual tree control when this item is visible, which
+ is different from the fake handle given to callers of a VirtualTree. */
+ Item* parent;
+ Item* prev;
+ Item* next;
+ Item* firstChild;
+ Item* lastChild;
+ UINT mask;
+ UINT state;
+ boost::optional<tstring> text;
+ int image;
+ int selectedImage;
+ LPARAM lParam;
+
+ Item();
+ Item(TVINSERTSTRUCT& tvis);
+
+ HTREEITEM ptr() const;
+
+ void insertBefore(Item* sibling);
+ void insertAfter(Item* sibling);
+ void setText(LPTSTR text);
+
+ bool expanded() const;
+ Item* lastExpandedChild() const;
+ Item* prevVisible() const;
+ Item* nextVisible() const;
+ };
+
+ std::list<Item> items;
+ Item* root;
+ Item* selected;
+
+ bool handleDelete(LPARAM lParam);
+ bool handleEnsureVisible(Item* item);
+ bool handleExpand(WPARAM code, Item* item);
+ void handleExpanded(NMTREEVIEW& data);
+ void handleExpanding(NMTREEVIEW& data);
+ bool handleGetItem(TVITEMEX& tv);
+ UINT handleGetItemState(UINT mask, Item* item);
+ Item* handleGetNextItem(WPARAM code, Item* item);
+ Item* handleInsert(TVINSERTSTRUCT& tvis);
+ bool handleSelect(WPARAM code, Item* item);
+ void handleSelected(Item* item);
+ bool handleSetItem(TVITEMEX& tv);
+
+ void addRoot();
+ bool validate(Item* item) const;
+ Item* find(HTREEITEM handle);
+ void display(Item& item);
+ void hide(Item& item);
+ void remove(Item* item);
+ void updateChildDisplay(Item* item);
+ LRESULT sendTreeMsg(UINT msg, WPARAM wParam, LPARAM lParam);
+};
+
+}
+
+#endif
=== added file 'dwt/src/widgets/VirtualTree.cpp'
--- dwt/src/widgets/VirtualTree.cpp 1970-01-01 00:00:00 +0000
+++ dwt/src/widgets/VirtualTree.cpp 2012-07-12 20:49:11 +0000
@@ -0,0 +1,485 @@
+/*
+ DC++ Widget Toolkit
+
+ Copyright (c) 2007-2012, Jacek Sieka
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the DWT nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <dwt/widgets/VirtualTree.h>
+
+#include <dwt/util/check.h>
+
+namespace dwt {
+
+VirtualTree::Seed::Seed(const BaseType::Seed& seed) :
+ BaseType::Seed(seed)
+{
+}
+
+VirtualTree::VirtualTree(Widget* parent) :
+ BaseType(parent),
+ selected(nullptr)
+{
+ addRoot();
+}
+
+bool VirtualTree::handleMessage(const MSG& msg, LRESULT& retVal) {
+ switch(msg.message) {
+ case TVM_DELETEITEM:
+ {
+ retVal = handleDelete(msg.lParam);
+ return true;
+ }
+ case TVM_ENSUREVISIBLE:
+ {
+ retVal = handleEnsureVisible(reinterpret_cast<Item*>(msg.lParam));
+ return true;
+ }
+ case TVM_EXPAND:
+ {
+ retVal = handleExpand(msg.wParam, reinterpret_cast<Item*>(msg.lParam));
+ return true;
+ }
+ case TVM_GETCOUNT:
+ {
+ retVal = items.size();
+ return true;
+ }
+ case TVM_GETITEM:
+ {
+ retVal = handleGetItem(*reinterpret_cast<TVITEMEX*>(msg.lParam));
+ return true;
+ }
+ case TVM_GETITEMSTATE:
+ {
+ retVal = handleGetItemState(msg.lParam, reinterpret_cast<Item*>(msg.wParam));
+ return true;
+ }
+ case TVM_GETNEXTITEM:
+ {
+ auto ret = handleGetNextItem(msg.wParam, reinterpret_cast<Item*>(msg.lParam));
+ retVal = ret == root ? 0 : reinterpret_cast<LRESULT>(ret);
+ return true;
+ }
+ case TVM_HITTEST:
+ {
+ retVal = reinterpret_cast<LRESULT>(find(reinterpret_cast<HTREEITEM>(sendTreeMsg(TVM_HITTEST, 0, msg.lParam))));
+ reinterpret_cast<TVHITTESTINFO*>(msg.lParam)->hItem = reinterpret_cast<HTREEITEM>(retVal);
+ return true;
+ }
+ case TVM_INSERTITEM:
+ {
+ retVal = reinterpret_cast<LRESULT>(handleInsert(*reinterpret_cast<TVINSERTSTRUCT*>(msg.lParam)));
+ return true;
+ }
+ case TVM_SELECTITEM:
+ {
+ retVal = handleSelect(msg.wParam, reinterpret_cast<Item*>(msg.lParam));
+ return true;
+ }
+ case TVM_SETITEM:
+ {
+ retVal = handleSetItem(*reinterpret_cast<TVITEMEX*>(msg.lParam));
+ return true;
+ }
+ case WM_NOTIFY:
+ {
+ switch(reinterpret_cast<NMHDR*>(msg.lParam)->code) {
+ case TVN_ITEMEXPANDED:
+ {
+ handleExpanded(*reinterpret_cast<NMTREEVIEW*>(msg.lParam));
+ break;
+ }
+ case TVN_ITEMEXPANDING:
+ {
+ handleExpanding(*reinterpret_cast<NMTREEVIEW*>(msg.lParam));
+ break;
+ }
+ case TVN_SELCHANGED:
+ {
+ handleSelected(find(reinterpret_cast<NMTREEVIEW*>(msg.lParam)->itemNew.hItem));
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return BaseType::handleMessage(msg, retVal);
+}
+
+// root node
+VirtualTree::Item::Item() :
+ handle(nullptr),
+ parent(nullptr),
+ prev(nullptr),
+ next(nullptr),
+ firstChild(nullptr),
+ lastChild(nullptr),
+ mask(0),
+ state(TVIS_EXPANDED),
+ image(0),
+ selectedImage(0),
+ lParam(0)
+{
+}
+
+VirtualTree::Item::Item(TVINSERTSTRUCT& tvis) :
+ handle(nullptr),
+ parent(reinterpret_cast<Item*>(tvis.hParent)),
+ prev(nullptr),
+ next(nullptr),
+ firstChild(nullptr),
+ lastChild(nullptr),
+ mask(tvis.itemex.mask),
+ state(tvis.itemex.state & tvis.itemex.stateMask),
+ image(tvis.itemex.iImage),
+ selectedImage(tvis.itemex.iSelectedImage),
+ lParam(tvis.itemex.lParam)
+{
+ if(tvis.hInsertAfter == TVI_FIRST) {
+ insertBefore(parent->firstChild);
+ } else if(tvis.hInsertAfter == TVI_LAST) {
+ insertAfter(parent->lastChild);
+ } else if(tvis.hInsertAfter == TVI_SORT) {
+ dwtDebugFail("VirtualTree TVI_SORT not implemented");
+ } else {
+ insertAfter(reinterpret_cast<Item*>(tvis.hInsertAfter));
+ }
+ setText(tvis.itemex.pszText);
+}
+
+HTREEITEM VirtualTree::Item::ptr() const {
+ return reinterpret_cast<HTREEITEM>(const_cast<Item*>(this));
+}
+
+void VirtualTree::Item::insertBefore(Item* sibling) {
+ if(sibling) {
+ if(sibling->prev) {
+ sibling->prev->next = this;
+ }
+ prev = sibling->prev;
+ sibling->prev = this;
+ }
+ next = sibling;
+ if(parent->firstChild == sibling) {
+ parent->firstChild = this;
+ }
+ if(!parent->lastChild) {
+ parent->lastChild = this;
+ }
+}
+
+void VirtualTree::Item::insertAfter(Item* sibling) {
+ if(sibling) {
+ if(sibling->next) {
+ sibling->next->prev = this;
+ }
+ next = sibling->next;
+ sibling->next = this;
+ }
+ prev = sibling;
+ if(parent->lastChild == sibling) {
+ parent->lastChild = this;
+ }
+ if(!parent->firstChild) {
+ parent->firstChild = this;
+ }
+}
+
+void VirtualTree::Item::setText(LPTSTR text) {
+ if(text && text != LPSTR_TEXTCALLBACK) {
+ this->text = text;
+ } else {
+ this->text.reset();
+ }
+}
+
+bool VirtualTree::Item::expanded() const {
+ return state & TVIS_EXPANDED;
+}
+
+VirtualTree::Item* VirtualTree::Item::lastExpandedChild() const {
+ return lastChild && expanded() ? lastChild->lastExpandedChild() : const_cast<Item*>(this);
+}
+
+VirtualTree::Item* VirtualTree::Item::prevVisible() const {
+ return prev ? prev->lastExpandedChild() : parent;
+}
+
+VirtualTree::Item* VirtualTree::Item::nextVisible() const {
+ if(firstChild && expanded()) { return firstChild; }
+ if(next) { return next; }
+ auto item = this;
+ while(item->parent) {
+ item = item->parent;
+ if(item->next) {
+ return item->next;
+ }
+ }
+ return nullptr;
+}
+
+bool VirtualTree::handleDelete(LPARAM lParam) {
+ if(!lParam || lParam == reinterpret_cast<LPARAM>(TVI_ROOT)) {
+ bool ret = sendTreeMsg(TVM_DELETEITEM, 0, lParam);
+ items.clear();
+ addRoot();
+ return ret;
+ }
+ auto item = reinterpret_cast<Item*>(lParam);
+ if(!validate(item)) { return false; }
+ hide(*item);
+ remove(item);
+ return true;
+}
+
+bool VirtualTree::handleEnsureVisible(Item* item) {
+ if(!validate(item)) { return false; }
+ display(*item);
+ return sendTreeMsg(TVM_ENSUREVISIBLE, 0, reinterpret_cast<LPARAM>(item->handle));
+}
+
+bool VirtualTree::handleExpand(WPARAM code, Item* item) {
+ if(!validate(item)) { return false; }
+ switch(code) {
+ case TVE_COLLAPSE: if(item->expanded()) { item->state &= ~TVIS_EXPANDED; } break;
+ case TVE_EXPAND: if(!item->expanded()) { item->state |= TVIS_EXPANDED; } break;
+ default: dwtDebugFail("VirtualTree expand code not implemented"); break;
+ }
+ if(item->handle) {
+ sendTreeMsg(TVM_EXPAND, code, reinterpret_cast<LPARAM>(item->handle));
+ }
+ return true;
+}
+
+void VirtualTree::handleExpanded(NMTREEVIEW& data) {
+ auto item = find(data.itemNew.hItem);
+ if(!validate(item)) { return; }
+ switch(data.action) {
+ case TVE_COLLAPSE:
+ {
+ if(item->expanded()) { item->state &= ~TVIS_EXPANDED; }
+ auto child = item->firstChild;
+ while(child) {
+ hide(*child);
+ child = child->next;
+ }
+ break;
+ }
+ case TVE_EXPAND:
+ {
+ if(!item->expanded()) { item->state |= TVIS_EXPANDED; }
+ break;
+ }
+ default: dwtDebugFail("VirtualTree expand code not implemented"); break;
+ }
+}
+
+void VirtualTree::handleExpanding(NMTREEVIEW& data) {
+ auto item = find(data.itemNew.hItem);
+ if(!validate(item)) { return; }
+ switch(data.action) {
+ case TVE_COLLAPSE:
+ {
+ break;
+ }
+ case TVE_EXPAND:
+ {
+ auto child = item->firstChild;
+ while(child) {
+ display(*child);
+ child = child->next;
+ }
+ break;
+ }
+ default: dwtDebugFail("VirtualTree expand code not implemented"); break;
+ }
+}
+
+bool VirtualTree::handleGetItem(TVITEMEX& tv) {
+ auto item = reinterpret_cast<Item*>(tv.hItem);
+ if(!validate(item)) { return false; }
+ if(tv.mask & TVIF_CHILDREN) { tv.cChildren = item->firstChild ? 1 : 0; }
+ if(tv.mask & TVIF_HANDLE) { tv.hItem = item->ptr(); }
+ if(tv.mask & TVIF_IMAGE) { tv.iImage = item->image; }
+ tv.lParam = item->lParam; // doesn't depend on TVIF_PARAM
+ if(tv.mask & TVIF_SELECTEDIMAGE) { tv.iSelectedImage = item->selectedImage; }
+ tv.state = item->state; // doesn't depend on TVIF_STATE nor on stateMask
+ if(tv.mask & TVIF_TEXT && item->text) { item->text->copy(tv.pszText, tv.cchTextMax); }
+ return true;
+}
+
+UINT VirtualTree::handleGetItemState(UINT mask, Item* item) {
+ if(!validate(item)) { return 0; }
+ return item->state & mask;
+}
+
+VirtualTree::Item* VirtualTree::handleGetNextItem(WPARAM code, Item* item) {
+ if(item && !validate(item)) { return nullptr; }
+ switch(code) {
+ case TVGN_CARET: return selected;
+ case TVGN_CHILD: return (item ? item : root)->firstChild;
+ case TVGN_DROPHILITE: return nullptr;
+ case TVGN_FIRSTVISIBLE: return root->firstChild;
+ case TVGN_LASTVISIBLE: return root->lastExpandedChild();
+ case TVGN_NEXT: return item ? item->next : nullptr;
+ //case TVGN_NEXTSELECTED: return selected;
+ case TVGN_NEXTVISIBLE: return item ? item->nextVisible() : nullptr;
+ case TVGN_PARENT: return item ? item->parent : nullptr;
+ case TVGN_PREVIOUS: return item ? item->prev : nullptr;
+ case TVGN_PREVIOUSVISIBLE: return item ? item->prevVisible() : nullptr;
+ case TVGN_ROOT: return root->firstChild;
+ default: return nullptr;
+ }
+}
+
+VirtualTree::Item* VirtualTree::handleInsert(TVINSERTSTRUCT& tvis) {
+ if(tvis.hParent == TVI_ROOT || !tvis.hParent) {
+ tvis.hParent = root->ptr();
+ }
+ items.emplace_back(tvis);
+ auto& item = items.back();
+ if(item.parent->firstChild == item.parent->lastChild) {
+ updateChildDisplay(item.parent);
+ }
+ if(item.parent->expanded()) {
+ display(item);
+ }
+ return &item;
+}
+
+bool VirtualTree::handleSelect(WPARAM code, Item* item) {
+ if(!validate(item)) { return sendTreeMsg(TVM_SELECTITEM, code, 0); }
+ display(*item);
+ return sendTreeMsg(TVM_SELECTITEM, code, reinterpret_cast<LPARAM>(item->handle));
+}
+
+void VirtualTree::handleSelected(Item* item) {
+ selected = validate(item) ? item : nullptr;
+}
+
+bool VirtualTree::handleSetItem(TVITEMEX& tv) {
+ auto item = reinterpret_cast<Item*>(tv.hItem);
+ if(!validate(item)) { return false; }
+ if(tv.mask & TVIF_IMAGE) { item->image = tv.iImage; }
+ if(tv.mask & TVIF_PARAM) { item->lParam = tv.lParam; }
+ if(tv.mask & TVIF_SELECTEDIMAGE) { item->selectedImage = tv.iSelectedImage; }
+ if(tv.mask & TVIF_STATE) { item->state &= ~tv.stateMask; item->state |= tv.state & tv.stateMask; }
+ if(tv.mask & TVIF_TEXT) { item->setText(tv.pszText); }
+ if(item->handle) {
+ tv.hItem = item->handle;
+ sendTreeMsg(TVM_SETITEM, 0, reinterpret_cast<LPARAM>(&tv));
+ }
+ return true;
+}
+
+void VirtualTree::addRoot() {
+ items.emplace_back();
+ root = &items.back();
+}
+
+bool VirtualTree::validate(Item* item) const {
+ return item;
+ /* ideally one would check that the item does point to an element of the "items" list, but
+ iterating through the list takes too long when it's a large one. */
+}
+
+VirtualTree::Item* VirtualTree::find(HTREEITEM handle) {
+ if(!handle) { return nullptr; }
+ for(auto& i: items) { if(i.handle == handle) { return &i; } }
+ return nullptr;
+}
+
+void VirtualTree::display(Item& item) {
+ if(item.handle) { return; }
+ if(item.parent != root && !item.parent->handle) { display(*item.parent); }
+ TVINSERTSTRUCT tvis = { item.parent->handle, item.prev ? item.prev->handle : item.next ? TVI_FIRST : TVI_LAST, { {
+ TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT } } };
+ auto expanded = item.expanded();
+ if(expanded) { item.state &= ~TVIS_EXPANDED; }
+ tvis.itemex.state = item.state;
+ tvis.itemex.stateMask = item.state;
+ tvis.itemex.pszText = item.text ? const_cast<TCHAR*>(item.text->c_str()) : LPSTR_TEXTCALLBACK;
+ tvis.itemex.iImage = item.image;
+ tvis.itemex.iSelectedImage = item.selectedImage;
+ tvis.itemex.cChildren = item.firstChild ? 1 : 0;
+ tvis.itemex.lParam = item.lParam;
+ item.handle = reinterpret_cast<HTREEITEM>(sendTreeMsg(TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>(&tvis)));
+ if(expanded) { sendTreeMsg(TVM_EXPAND, TVE_EXPAND, reinterpret_cast<LPARAM>(item.handle)); }
+}
+
+void VirtualTree::hide(Item& item) {
+ if(!item.handle) { return; }
+ auto child = item.firstChild;
+ while(child) {
+ hide(*child);
+ child = child->next;
+ }
+ sendTreeMsg(TVM_DELETEITEM, 0, reinterpret_cast<LPARAM>(item.handle));
+ item.handle = nullptr;
+}
+
+void VirtualTree::remove(Item* item) {
+ while(item->firstChild) {
+ remove(item->firstChild);
+ }
+ if(item->parent) {
+ if(item->parent->firstChild == item) {
+ item->parent->firstChild = item->next;
+ if(!item->parent->firstChild) {
+ updateChildDisplay(item->parent);
+ }
+ }
+ if(item->parent->lastChild == item) {
+ item->parent->lastChild = item->prev;
+ }
+ }
+ if(item->prev) { item->prev->next = item->next; }
+ if(item->next) { item->next->prev = item->prev; }
+ if(item == selected) { selected = nullptr; }
+ for(auto i = items.begin(), iend = items.end(); i != iend; ++i) {
+ if(&*i == item) {
+ items.erase(i);
+ break;
+ }
+ }
+}
+
+void VirtualTree::updateChildDisplay(Item* item) {
+ if(!item->handle) { return; }
+ TVITEMEX tv = { TVIF_CHILDREN, item->handle };
+ tv.cChildren = item->firstChild ? 1 : 0;
+ sendTreeMsg(TVM_SETITEM, 0, reinterpret_cast<LPARAM>(&tv));
+}
+
+LRESULT VirtualTree::sendTreeMsg(UINT msg, WPARAM wParam, LPARAM lParam) {
+ // send with a direct dispatcher call to avoid loops (since we catch tree messages).
+ MSG treeMsg = { treeHandle(), msg, wParam, lParam };
+ return tree->getDispatcher().chain(treeMsg);
+}
+
+}
=== modified file 'win32/DirectoryListingFrame.cpp'
--- win32/DirectoryListingFrame.cpp 2012-07-12 17:50:02 +0000
+++ win32/DirectoryListingFrame.cpp 2012-07-12 20:49:11 +0000
@@ -37,7 +37,7 @@
#include <dwt/widgets/SaveDialog.h>
#include <dwt/widgets/SplitterContainer.h>
#include <dwt/widgets/ToolBar.h>
-#include <dwt/widgets/Tree.h>//#include <dwt/widgets/VirtualTree.h>
+#include <dwt/widgets/VirtualTree.h>
#include "TypedTable.h"
#include "TypedTree.h"
@@ -439,6 +439,7 @@
ErrorF errorF;
void cacheInfo(DirectoryListing::Directory* d) {
+ if(parent.dl->getAbort()) { throw Exception(); }
for(auto i: d->directories) {
parent.dirCache[i] = make_unique<DirectoryListingFrame::ItemInfo>(i);
cacheInfo(i);
@@ -494,6 +495,7 @@
// error callback
error = std::move(s);
finishLoad();
+ dirCache.clear();
}); });
try {
=== modified file 'win32/DirectoryListingFrame.h'
--- win32/DirectoryListingFrame.h 2012-07-12 17:50:02 +0000
+++ win32/DirectoryListingFrame.h 2012-07-12 20:49:11 +0000
@@ -174,7 +174,7 @@
ComboBoxPtr searchBox;
ComboBoxPtr filterMethod;
- typedef TypedTree<ItemInfo, true/*, dwt::VirtualTree*/> WidgetDirs;
+ typedef TypedTree<ItemInfo, true, dwt::VirtualTree> WidgetDirs;
typedef WidgetDirs* WidgetDirsPtr;
WidgetDirsPtr dirs;