← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 2810: Play with trees

 

------------------------------------------------------------
revno: 2810
committer: Jacek Sieka <arnetheduck@xxxxxxxxx>
branch nick: dcplusplus
timestamp: Wed 2012-01-11 21:53:02 +0100
message:
  Play with trees
added:
  dwt/include/dwt/widgets/Header.h
  dwt/src/widgets/Header.cpp
  dwt/test/TreeTest.cpp
modified:
  dwt/include/dwt/forward.h
  dwt/include/dwt/widgets/ModalDialog.h
  dwt/include/dwt/widgets/ModelessDialog.h
  dwt/include/dwt/widgets/Tree.h
  dwt/src/widgets/ModalDialog.cpp
  dwt/src/widgets/ModelessDialog.cpp
  dwt/src/widgets/Tree.cpp
  test/SConscript
  win32/TypedTree.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 'dwt/include/dwt/forward.h'
--- dwt/include/dwt/forward.h	2011-05-07 18:52:09 +0000
+++ dwt/include/dwt/forward.h	2012-01-11 20:53:02 +0000
@@ -66,6 +66,9 @@
 class Container;
 typedef Container* ContainerPtr;
 
+class Control;
+typedef Control* ControlPtr;
+
 class CoolBar;
 typedef CoolBar* CoolBarPtr;
 
@@ -89,6 +92,9 @@
 class GroupBox;
 typedef GroupBox* GroupBoxPtr;
 
+class Header;
+typedef Header* HeaderPtr;
+
 class Icon;
 typedef boost::intrusive_ptr<Icon> IconPtr;
 

=== added file 'dwt/include/dwt/widgets/Header.h'
--- dwt/include/dwt/widgets/Header.h	1970-01-01 00:00:00 +0000
+++ dwt/include/dwt/widgets/Header.h	2012-01-11 20:53:02 +0000
@@ -0,0 +1,129 @@
+/*
+  DC++ Widget Toolkit
+
+  Copyright (c) 2007-2011, 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 SmartWin++ 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_HEADER_H_
+#define DWT_HEADER_H_
+
+#include "Control.h"
+
+#include "../aspects/Collection.h"
+#include "../aspects/Data.h"
+
+namespace dwt {
+
+/** Header control like the one used for Table */
+class Header :
+	public CommonControl,
+	public aspects::Collection<Header, int>,
+	public aspects::Data<Header, int>
+{
+	typedef CommonControl BaseType;
+
+	friend class WidgetCreator<Header>;
+	friend class aspects::Collection<Header, int>;
+	friend class aspects::Data<Header, int>;
+public:
+	/// Class type
+	typedef Header ThisType;
+
+	/// Object type
+	typedef ThisType* ObjectType;
+
+	/// Seed class
+	/** This class contains all of the values needed to create the widget. It also
+	  * knows the type of the class whose seed values it contains. Every widget
+	  * should define one of these.
+	  */
+	struct Seed : public BaseType::Seed {
+		typedef ThisType WidgetType;
+
+		/// Fills with default parameters
+		Seed();
+	};
+
+	/// Actually creates the Header
+	void create( const Seed & cs = Seed() );
+
+	int insert(const tstring& header, int width, LPARAM lParam = 0, int after = -1);
+
+	virtual Point getPreferredSize();
+
+protected:
+	/// Constructor Taking pointer to parent
+	explicit Header( Widget * parent );
+
+	// Protected to avoid direct instantiation, you can inherit and use
+	// WidgetFactory class which is friend
+	virtual ~Header()
+	{}
+
+private:
+	friend class ChainingDispatcher;
+	static const TCHAR windowClass[];
+
+	// aspects::Collection
+	void eraseImpl(int row);
+	void clearImpl();
+	size_t sizeImpl() const;
+
+	// aspects::Data
+	int findDataImpl(LPARAM data, int start = -1);
+	LPARAM getDataImpl(int idx);
+	void setDataImpl(int i, LPARAM data);
+
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Implementation of class
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+inline Header::Header( Widget * parent )
+	: BaseType(parent, ChainingDispatcher::superClass<Header>())
+{
+}
+
+inline void Header::eraseImpl( int row ) {
+	Header_DeleteItem(handle(), row);
+}
+
+inline size_t Header::sizeImpl() const {
+	return Header_GetItemCount(handle());
+}
+
+inline void Header::clearImpl() {
+	for(size_t i = 0, iend = size(); i < iend; ++i) {
+		erase(0);
+	}
+}
+
+}
+
+#endif /* HEADER_H_ */

=== modified file 'dwt/include/dwt/widgets/ModalDialog.h'
--- dwt/include/dwt/widgets/ModalDialog.h	2011-11-07 22:11:39 +0000
+++ dwt/include/dwt/widgets/ModalDialog.h	2012-01-11 20:53:02 +0000
@@ -129,7 +129,7 @@
 	virtual void kill();
 private:
 	friend class ChainingDispatcher;
-	static LPCTSTR windowClass;
+	static const TCHAR* windowClass;
 
 	bool quit;
 	int ret;

=== modified file 'dwt/include/dwt/widgets/ModelessDialog.h'
--- dwt/include/dwt/widgets/ModelessDialog.h	2011-11-07 20:53:49 +0000
+++ dwt/include/dwt/widgets/ModelessDialog.h	2012-01-11 20:53:02 +0000
@@ -79,7 +79,7 @@
 
 private:
 	friend class ChainingDispatcher;
-	static LPCTSTR windowClass;
+	static const TCHAR *windowClass;
 };
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

=== modified file 'dwt/include/dwt/widgets/Tree.h'
--- dwt/include/dwt/widgets/Tree.h	2011-11-19 00:10:54 +0000
+++ dwt/include/dwt/widgets/Tree.h	2012-01-11 20:53:02 +0000
@@ -3,10 +3,6 @@
 
   Copyright (c) 2007-2011, Jacek Sieka
 
-  SmartWin++
-
-  Copyright (c) 2005 Thomas Hansen
-
   All rights reserved.
 
   Redistribution and use in source and binary forms, with or without modification,
@@ -33,13 +29,14 @@
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
-#ifndef DWT_Tree_h
-#define DWT_Tree_h
+#ifndef DWT_TREE_H
+#define DWT_TREE_H
 
 #include "../Rectangle.h"
 #include "../resources/ImageList.h"
 #include "../aspects/Clickable.h"
 #include "../aspects/Collection.h"
+#include "../aspects/Columns.h"
 #include "../aspects/CustomDraw.h"
 #include "../aspects/Data.h"
 #include "../aspects/Selection.h"
@@ -60,29 +57,48 @@
 	HTREEITEM handle;
 };
 
-/// TreeView class
  /** \ingroup WidgetControls
    * \WidgetUsageInfo
-   * \image html treeview.PNG
-   * A Tree is a treview control, like for instance the documentation to
-   * dwt which you are probably reading right now would ( in the web version )
-   * have a tree view to the left. <br>
-   * Another good example of a tree view is the Explorer of Windows, it has a tree
-   * view to the left where you can see the different directories.
    */
 class Tree :
-	public CommonControl,
+	public Control,
 	public aspects::Clickable<Tree>,
 	public aspects::Collection<Tree, HTREEITEM>,
-	public aspects::CustomDraw<Tree, NMTVCUSTOMDRAW>,
+	public aspects::Columns<Tree>,
 	public aspects::Data<Tree, HTREEITEM>,
 	public aspects::Selection<Tree, HTREEITEM>
 {
-	typedef CommonControl BaseType;
+	typedef Control BaseType;
+
+	class TreeView :
+		public Control,
+		public aspects::CustomDraw<TreeView, NMTVCUSTOMDRAW>
+		{
+		friend class WidgetCreator<TreeView>;
+	public:
+		typedef Tree::Seed Seed;
+		typedef Control BaseType;
+
+		/// Class type
+		typedef TreeView ThisType;
+
+		/// Object type
+		typedef ThisType* ObjectType;
+
+		static const TCHAR windowClass[];
+
+		TreeView(Widget* parent);
+
+		/// Returns true if handled, else false
+		virtual bool handleMessage(const MSG &msg, LRESULT &retVal);
+	};
+
+	typedef TreeView* TreeViewPtr;
 
 protected:
 	friend class WidgetCreator<Tree>;
 	friend class aspects::Collection<Tree, HTREEITEM>;
+	friend class aspects::Columns<Tree>;
 	friend class aspects::Data<Tree, HTREEITEM>;
 	friend class aspects::Selection<Tree, HTREEITEM>;
 	friend class aspects::Clickable<Tree>;
@@ -109,21 +125,6 @@
 	};
 
 	/// Inserts a "node" into the TreeView
-	/** The return value from a call to this function is a Node. <br>
-	  * If you later wish to inserts CHILDREN to that node, pass the return value
-	  * from the first call as the second parameter into this function. <br>
-	  * If you wish to insert a ( a TreeView can have several "root" nodes ) "root"
-	  * node then don't pass anything as the second parameter. ( or pass Node() )
-	  * <br>
-	  * The "param" parameter ( optionally ) is a unique unsigned integer which must
-	  * be higher than 0 and can later be used to retrieve unique identification of
-	  * which item was e.g. selected etc... <br>
-	  * Especially useful when text of nodes is not unique or text might change.
-	  * The "iconIndex" optionally specifies the icon index of the item in the
-	  * associated image list, if there is one. <br>
-	  * The "selectedIconIndex" optionally specifies the icon index of the item in the
-	  * selected state (if not specified or -1, it defaults to the iconIndex)
-	  */
 	HTREEITEM insert(const tstring& text, HTREEITEM parent = NULL, LPARAM param = 0, bool expanded = false, int iconIndex = - 1, int selectedIconIndex = - 1);
 
 	HTREEITEM getNext(HTREEITEM node, unsigned flag);
@@ -225,9 +226,6 @@
 	  */
 	tstring getText( HTREEITEM node );
 
-	/// Returns true if fired, else false
-	virtual bool handleMessage( const MSG & msg, LRESULT & retVal );
-
 	/// Actually creates the TreeView
 	/** You should call WidgetFactory::createTreeView if you instantiate class
 	  * directly. <br>
@@ -235,6 +233,7 @@
 	  */
 	void create( const Seed & cs = Seed() );
 
+	virtual void layout();
 protected:
 	// Constructor Taking pointer to parent
 	explicit Tree( Widget * parent );
@@ -244,13 +243,16 @@
 	virtual ~Tree()
 	{}
 
+	HWND treeHandle() const { return tree->handle(); }
 private:
-	friend class ChainingDispatcher;
-	static const TCHAR windowClass[];
-
 	ImageListPtr itsNormalImageList;
 	ImageListPtr itsStateImageList;
 
+	TreeViewPtr tree;
+	HeaderPtr header;
+
+	HeaderPtr getHeader();
+
 	// aspects::Data
 	LPARAM getDataImpl(HTREEITEM item);
 	void setDataImpl(HTREEITEM item, LPARAM data);
@@ -273,81 +275,90 @@
 	static Message getClickMessage();
 	static Message getRightClickMessage();
 	static Message getDblClickMessage();
+
+	// aspects::Columns
+	int insertColumnImpl(const Column& column, int after);
+	void eraseColumnImpl(unsigned column);
+	unsigned getColumnCountImpl() const;
+	std::vector<Column> getColumnsImpl() const;
+	Column getColumnImpl(unsigned column) const;
+	std::vector<int> getColumnOrderImpl() const;
+	void setColumnOrderImpl(const std::vector<int>& columns);
+	std::vector<int> getColumnWidthsImpl() const;
+	void setColumnWidthImpl( unsigned column, int width );
+
+	LRESULT draw(NMTVCUSTOMDRAW& x);
 };
 
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// Implementation of class
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
 inline HTREEITEM Tree::getNext( HTREEITEM node, unsigned flag ) {
-	return TreeView_GetNextItem( handle(), node, flag );
+	return TreeView_GetNextItem(treeHandle(), node, flag);
 }
 
 inline HTREEITEM Tree::getChild(HTREEITEM node) {
-	return TreeView_GetChild(handle(), node);
+	return TreeView_GetChild(treeHandle(), node);
 }
 
 inline HTREEITEM Tree::getNextSibling(HTREEITEM node) {
-	return TreeView_GetNextSibling(handle(), node);
+	return TreeView_GetNextSibling(treeHandle(), node);
 }
 
 inline HTREEITEM Tree::getParent(HTREEITEM node) {
-	return TreeView_GetParent(handle(), node);
+	return TreeView_GetParent(treeHandle(), node);
 }
 
 inline HTREEITEM Tree::getRoot() {
-	return TreeView_GetRoot(handle());
+	return TreeView_GetRoot(treeHandle());
 }
 
 inline HTREEITEM Tree::getFirst() {
-	return TreeView_GetFirstVisible(handle());
+	return TreeView_GetFirstVisible(treeHandle());
 }
 
 inline HTREEITEM Tree::getLast() {
-	return TreeView_GetLastVisible(handle());
+	return TreeView_GetLastVisible(treeHandle());
 }
 
 inline void Tree::setColorImpl(COLORREF text, COLORREF background) {
-	TreeView_SetTextColor(handle(), text);
-	TreeView_SetBkColor(handle(), background);
+	TreeView_SetTextColor(treeHandle(), text);
+	TreeView_SetBkColor(treeHandle(), background);
 }
 
 inline HTREEITEM Tree::hitTest(const ScreenCoordinate& pt) {
 	ClientCoordinate cc(pt, this);
 	TVHITTESTINFO tvhti = { cc.getPoint() };
-	return TreeView_HitTest(handle(), &tvhti);
+	return TreeView_HitTest(treeHandle(), &tvhti);
 }
 
 inline bool Tree::isExpanded(HTREEITEM node) {
-	return TreeView_GetItemState(handle(), node, TVIS_EXPANDED) & TVIS_EXPANDED;
+	return TreeView_GetItemState(treeHandle(), node, TVIS_EXPANDED) & TVIS_EXPANDED;
 }
 
 inline void Tree::expand(HTREEITEM node) {
-	TreeView_Expand(handle(), node, TVE_EXPAND);
+	TreeView_Expand(treeHandle(), node, TVE_EXPAND);
 }
 
 inline void Tree::collapse(HTREEITEM node) {
-	TreeView_Expand(handle(), node, TVE_COLLAPSE);
+	TreeView_Expand(treeHandle(), node, TVE_COLLAPSE);
 }
 
 inline void Tree::clearImpl() {
-	TreeView_DeleteAllItems( handle() );
+	TreeView_DeleteAllItems(treeHandle());
 }
 
 inline void Tree::eraseImpl( HTREEITEM node ) {
-	TreeView_DeleteItem( handle(), node );
+	TreeView_DeleteItem(treeHandle(), node);
 }
 
 inline size_t Tree::sizeImpl() const {
-	return static_cast<size_t>(TreeView_GetCount(handle()));
+	return static_cast<size_t>(TreeView_GetCount(treeHandle()));
 }
 
 inline void Tree::editLabel( HTREEITEM node ) {
-	static_cast<void>(TreeView_EditLabel( handle(), node ));
+	static_cast<void>(TreeView_EditLabel(treeHandle(), node));
 }
 
 inline void Tree::ensureVisible( HTREEITEM node ) {
-	TreeView_EnsureVisible( handle(), node );
+	TreeView_EnsureVisible(treeHandle(), node);
 }
 
 inline void Tree::setHasButtons( bool value ) {
@@ -391,11 +402,11 @@
 }
 
 inline HTREEITEM Tree::getSelectedImpl() const {
-	return TreeView_GetSelection( handle() );
+	return TreeView_GetSelection(treeHandle());
 }
 
 inline void Tree::setSelectedImpl(HTREEITEM item) {
-	TreeView_SelectItem( handle(), item );
+	TreeView_SelectItem(treeHandle(), item );
 }
 
 inline size_t Tree::countSelectedImpl() const {
@@ -403,7 +414,7 @@
 }
 
 inline Tree::Tree( Widget * parent )
-	: BaseType(parent, ChainingDispatcher::superClass<Tree>())
+	: BaseType(parent, NormalDispatcher::newClass<Tree>()), tree(nullptr), header(nullptr)
 {
 }
 

=== added file 'dwt/src/widgets/Header.cpp'
--- dwt/src/widgets/Header.cpp	1970-01-01 00:00:00 +0000
+++ dwt/src/widgets/Header.cpp	2012-01-11 20:53:02 +0000
@@ -0,0 +1,97 @@
+/*
+  DC++ Widget Toolkit
+
+  Copyright (c) 2007-2011, 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/Header.h>
+
+namespace dwt {
+
+const TCHAR Header::windowClass[] = WC_HEADER;
+
+Header::Seed::Seed() :
+BaseType::Seed(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS)
+{
+}
+
+void Header::create( const Header::Seed & cs ) {
+	BaseType::create(cs);
+}
+
+Point Header::getPreferredSize() {
+	RECT rc = { 0, 0, ::GetSystemMetrics(SM_CXSCREEN), ::GetSystemMetrics(SM_CYSCREEN) };
+	WINDOWPOS wp = { 0 };
+	HDLAYOUT hl = { &rc, &wp };
+	if(Header_Layout(handle(), &hl)) {
+		return Point(wp.cx, wp.cy);
+	}
+
+	return Point(0, 0);
+}
+
+int Header::insert(const tstring& header, int width, LPARAM lParam, int after) {
+	if(after == -1) after = size();
+
+	HDITEM item = { HDI_FORMAT };
+	item.fmt = HDF_LEFT;// TODO
+	if(!header.empty()) {
+		item.mask |= HDI_TEXT;
+		item.pszText = const_cast<LPTSTR>(header.c_str());
+	}
+
+	if(width >= 0) {
+		item.mask |= HDI_WIDTH;
+		item.cxy = width;
+	}
+
+	return Header_InsertItem(handle(), after, &item);
+}
+
+int Header::findDataImpl(LPARAM data, int start) {
+    LVFINDINFO fi = { LVFI_PARAM, NULL, data };
+    return ListView_FindItem(handle(), start, &fi);
+}
+
+LPARAM Header::getDataImpl(int idx) {
+	HDITEM item = { HDI_LPARAM };
+
+	if(!Header_GetItem(handle(), idx, &item)) {
+		return 0;
+	}
+	return item.lParam;
+}
+
+void Header::setDataImpl(int idx, LPARAM data) {
+	LVITEM item = { HDI_LPARAM };
+	item.lParam = data;
+
+	Header_SetItem(handle(), idx, &item);
+}
+
+}

=== modified file 'dwt/src/widgets/ModalDialog.cpp'
--- dwt/src/widgets/ModalDialog.cpp	2011-07-05 12:16:32 +0000
+++ dwt/src/widgets/ModalDialog.cpp	2012-01-11 20:53:02 +0000
@@ -36,7 +36,7 @@
 
 namespace dwt {
 
-LPCTSTR ModalDialog::windowClass = WC_DIALOG;
+const TCHAR* ModalDialog::windowClass = WC_DIALOG;
 
 ModalDialog::Seed::Seed(const Point& size, DWORD styles_) :
 BaseType::Seed(tstring(), styles_ | WS_POPUP | WS_CAPTION | WS_SYSMENU, WS_EX_CONTROLPARENT | WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE)

=== modified file 'dwt/src/widgets/ModelessDialog.cpp'
--- dwt/src/widgets/ModelessDialog.cpp	2011-01-02 17:12:02 +0000
+++ dwt/src/widgets/ModelessDialog.cpp	2012-01-11 20:53:02 +0000
@@ -33,7 +33,7 @@
 
 namespace dwt {
 
-LPCTSTR ModelessDialog::windowClass = WC_DIALOG;
+const TCHAR *ModelessDialog::windowClass = WC_DIALOG;
 
 ModelessDialog::Seed::Seed(const Point& size, DWORD styles_) :
 BaseType::Seed(tstring(), styles_ | DS_CONTROL | WS_CHILD, WS_EX_CONTROLPARENT)

=== modified file 'dwt/src/widgets/Tree.cpp'
--- dwt/src/widgets/Tree.cpp	2011-06-28 20:07:49 +0000
+++ dwt/src/widgets/Tree.cpp	2012-01-11 20:53:02 +0000
@@ -30,10 +30,33 @@
 */
 
 #include <dwt/widgets/Tree.h>
+#include <dwt/widgets/Header.h>
+#include <dwt/WidgetCreator.h>
 
 namespace dwt {
 
-const TCHAR Tree::windowClass[] = WC_TREEVIEW;
+const TCHAR Tree::TreeView::windowClass[] = WC_TREEVIEW;
+
+Tree::TreeView::TreeView(Widget* parent) : Control(parent, ChainingDispatcher::superClass<TreeView>()) { }
+
+bool Tree::TreeView::handleMessage(const MSG& msg, LRESULT &retVal) {
+	if(BaseType::handleMessage(msg, retVal)) {
+		return true;
+	}
+
+	if(msg.message == WM_NOTIFY) {
+		// Forward tree notifications
+		return getParent()->handleMessage(msg, retVal);
+	}
+
+	if(msg.message == WM_RBUTTONDOWN) {
+		// Tree view control does strange things to rbuttondown, preventing wm_contextmenu from reaching it
+		retVal = ::DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
+		return true;
+	}
+
+	return false;
+}
 
 Tree::Seed::Seed() :
 	BaseType::Seed(WS_CHILD | WS_TABSTOP | TVS_DISABLEDRAGDROP | TVS_HASLINES | TVS_NONEVENHEIGHT | TVS_SHOWSELALWAYS),
@@ -43,8 +66,17 @@
 
 void Tree::create( const Seed & cs )
 {
-	BaseType::create(cs);
+	Control::Seed mySeed(WS_CHILD);
+
+	BaseType::create(mySeed);
+	tree = WidgetCreator<TreeView>::create(this, cs);
+
+	onSized([&](const SizedEvent& e) { layout(); });
+
+	tree->onCustomDraw([=](NMTVCUSTOMDRAW& x) { return draw(x); });
+
 	setFont(cs.font);
+	layout();
 }
 
 HTREEITEM Tree::insert(const tstring& text, HTREEITEM parent, LPARAM param, bool expanded, int iconIndex, int selectedIconIndex) {
@@ -73,11 +105,11 @@
 #else
 	tv.itemex = t;
 #endif
-	return TreeView_InsertItem(handle(), &tv);
+	return TreeView_InsertItem(treeHandle(), &tv);
 }
 
 tstring Tree::getSelectedText() {
-	return getText(TreeView_GetSelection(handle()));
+	return getText(TreeView_GetSelection(treeHandle()));
 }
 
 tstring Tree::getText( HTREEITEM node )
@@ -91,7 +123,7 @@
 	buffer[0] = '\0';
 	item.cchTextMax = 1022;
 	item.pszText = buffer;
-	if ( TreeView_GetItem(handle(), &item) )
+	if ( TreeView_GetItem(treeHandle(), &item) )
 	{
 		return buffer;
 	}
@@ -116,17 +148,17 @@
 
 void Tree::setNormalImageList( ImageListPtr imageList ) {
 	  itsNormalImageList = imageList;
-	  TreeView_SetImageList(handle(), imageList->getImageList(), TVSIL_NORMAL);
+	  TreeView_SetImageList(treeHandle(), imageList->getImageList(), TVSIL_NORMAL);
 }
 
 void Tree::setStateImageList( ImageListPtr imageList ) {
 	  itsStateImageList = imageList;
-	  TreeView_SetImageList(handle(), imageList->getImageList(), TVSIL_STATE);
+	  TreeView_SetImageList(treeHandle(), imageList->getImageList(), TVSIL_STATE);
 }
 
 LPARAM Tree::getDataImpl(HTREEITEM item) {
 	TVITEM tvitem = { TVIF_PARAM | TVIF_HANDLE, item };
-	if(!TreeView_GetItem(handle(), &tvitem)) {
+	if(!TreeView_GetItem(treeHandle(), &tvitem)) {
 		return 0;
 	}
 	return tvitem.lParam;
@@ -135,15 +167,15 @@
 void Tree::setDataImpl(HTREEITEM item, LPARAM lParam) {
 	TVITEM tvitem = { TVIF_PARAM | TVIF_HANDLE, item };
 	tvitem.lParam = lParam;
-	TreeView_SetItem(handle(), &tvitem);
+	TreeView_SetItem(treeHandle(), &tvitem);
 }
 
 int Tree::getItemHeight() {
-	return TreeView_GetItemHeight(handle());
+	return TreeView_GetItemHeight(treeHandle());
 }
 
 void Tree::setItemHeight(int h) {
-	TreeView_SetItemHeight(handle(), h);
+	TreeView_SetItemHeight(treeHandle(), h);
 }
 
 ScreenCoordinate Tree::getContextMenuPos() {
@@ -166,19 +198,105 @@
 
 Rectangle Tree::getItemRect(HTREEITEM item) {
 	RECT rc;
-	TreeView_GetItemRect(handle(), item, &rc, TRUE);
+	TreeView_GetItemRect(treeHandle(), item, &rc, TRUE);
 	return Rectangle(rc);
 }
 
-/// Returns true if fired, else false
-bool Tree::handleMessage( const MSG & msg, LRESULT & retVal ) {
-	bool handled = BaseType::handleMessage(msg, retVal);
-	if(!handled && msg.message == WM_RBUTTONDOWN) {
-		// Tree view control does strange things to rbuttondown, preventing wm_contextmenu from reaching it
-		retVal = ::DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
-		return true;
-	}
-	return handled;
+HeaderPtr Tree::getHeader() {
+	if(header == NULL) {
+		header = WidgetCreator<Header>::create(this);
+		layout();
+	}
+
+	return header;
+}
+
+void Tree::layout() {
+	auto client = getClientSize();
+	if(header) {
+		auto hsize = header->getPreferredSize();
+		header->resize(Rectangle(0, 0, client.x, hsize.y));
+		tree->resize(Rectangle(0, hsize.y, client.x, client.y - hsize.y));
+	} else {
+		tree->resize(Rectangle(client));
+	}
+}
+
+int Tree::insertColumnImpl(const Column& column, int after) {
+	auto h = getHeader();
+
+	return h->insert(column.header, column.width, 0, after);
+}
+
+void Tree::eraseColumnImpl(unsigned column) {
+	if(!header) {
+		return;
+	}
+
+	header->erase(column);
+	if(getColumnCount() == 0) {
+		header->close(false);
+		header = 0;
+
+		layout();
+	}
+}
+
+unsigned Tree::getColumnCountImpl() const {
+	return header ? header->size() : 0;
+}
+
+Column Tree::getColumnImpl(unsigned column) const {
+	if(!header) {
+		return Column();
+	}
+
+	HDITEM item = { HDI_FORMAT | HDI_TEXT | HDI_WIDTH };
+	TCHAR buf[1024] = { 0 };
+	item.pszText = buf;
+	item.cchTextMax = 1023;
+	Header_GetItem(header->handle(), column, &item);
+
+	return Column(item.pszText, item.cxy); // TODO fmt
+}
+
+std::vector<Column> Tree::getColumnsImpl() const {
+	std::vector<Column> ret;
+	if(!header) {
+		return ret;
+	}
+
+	ret.resize(getColumnCount());
+	for(size_t i = 0; i < ret.size(); ++i) {
+		ret[i] = getColumn(i);
+	}
+
+	return ret;
+}
+
+std::vector<int> Tree::getColumnOrderImpl() const {
+	return std::vector<int>(); // TODO
+}
+
+void Tree::setColumnOrderImpl(const std::vector<int>& columns) {
+	// TODO
+}
+
+std::vector<int> Tree::getColumnWidthsImpl() const {
+	return std::vector<int>(); // TODO
+}
+
+void Tree::setColumnWidthImpl(unsigned column, int width) {
+	// TODO
+}
+
+LRESULT Tree::draw(NMTVCUSTOMDRAW& x) {
+	if(getColumnCount() < 2) {
+		return CDRF_DODEFAULT;
+	}
+
+	//TODO
+	return CDRF_DODEFAULT;
 }
 
 }

=== added file 'dwt/test/TreeTest.cpp'
--- dwt/test/TreeTest.cpp	1970-01-01 00:00:00 +0000
+++ dwt/test/TreeTest.cpp	2012-01-11 20:53:02 +0000
@@ -0,0 +1,49 @@
+#include <dwt/widgets/Window.h>
+#include <dwt/widgets/Tree.h>
+#include <dwt/Texts.h>
+
+#include <iostream>
+
+namespace dwt {
+tstring Texts::get(Text text) { return _T("test"); }
+}
+
+using dwt::tstring;
+
+int dwtMain(dwt::Application& app)
+{
+	auto window = new dwt::Window();
+	window->create();
+	window->onClosing([] { return ::PostQuitMessage(0), true; });
+
+	auto tree = window->addChild(dwt::Tree::Seed());
+	//tree.setHeaderVisible(true);
+
+	tree->addColumn(_T("Column 1"), 200, dwt::Column::LEFT);
+	tree->addColumn(_T("Column 2"), 200, dwt::Column::CENTER);
+	tree->addColumn(_T("Column 3"), 200, dwt::Column::RIGHT);
+
+	for (int i = 0; i < 4; i++) {
+		tstring name(_T("item 1"));
+		name.back() += i;
+
+		auto item = tree->insert(name, NULL, 1);
+		assert(tree->getData(item) == 1);
+		for (int j = 0; j < 4; j++) {
+			tstring subname(_T("item 1"));
+			subname.back() += j;
+			auto subItem = tree->insert(subname, item);
+
+		}
+	}
+
+	tree->resize(dwt::Rectangle(window->getClientSize()));
+
+	app.run();
+
+	return 0;
+}
+
+
+
+

=== modified file 'test/SConscript'
--- test/SConscript	2012-01-10 18:45:17 +0000
+++ test/SConscript	2012-01-11 20:53:02 +0000
@@ -3,6 +3,11 @@
 Import('dev source_path')
 
 def runUnitTest(env,target,source):
+	import sys
+	if sys.platform != 'win32':
+		open(str(target[0]),'w').write("SKIPPED\n")
+		return
+		
 	import subprocess
 	app = str(source[0].abspath)
 	if not subprocess.call(app):

=== modified file 'win32/TypedTree.h'
--- win32/TypedTree.h	2011-12-26 16:12:50 +0000
+++ win32/TypedTree.h	2012-01-11 20:53:02 +0000
@@ -77,7 +77,7 @@
 	}
 
 	HTREEITEM insert(TVINSERTSTRUCT* tvis) {
-		return TreeView_InsertItem(this->handle(), tvis);
+		return TreeView_InsertItem(this->treeHandle(), tvis);
 	}
 
 	ContentType* getData(HTREEITEM item) {
@@ -85,7 +85,7 @@
 	}
 
 	void getItem(TVITEMEX* item) {
-		TreeView_GetItem(this->handle(), item);
+		TreeView_GetItem(this->treeHandle(), item);
 	}
 
 	ContentType* getSelectedData() {
@@ -94,7 +94,7 @@
 	}
 
 	void setItemState(HTREEITEM item, int state, int mask) {
-		TreeView_SetItemState(this->handle(), item, state, mask);
+		TreeView_SetItemState(this->treeHandle(), item, state, mask);
 	}
 
 	void clear() {