Upstream tarball 9440
[amule.git] / src / DirectoryTreeCtrl.cpp
blob535e572e09a280be952b589b772b65647977aead
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2003-2008 Robert Rostek ( tecxx@rrs.at )
6 // Copyright (c) 2002-2008 Merkur ( devs@emule-project.net / http://www.emule-project.net )
7 //
8 // Any parts of this program derived from the xMule, lMule or eMule project,
9 // or contributed by third-party developers are copyrighted by their
10 // respective authors.
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "DirectoryTreeCtrl.h" // Interface declarations
29 #include <wx/app.h>
30 #include <wx/filename.h>
31 #include <wx/imaglist.h>
33 #include <common/StringFunctions.h>
34 #include <common/FileFunctions.h>
35 #include "muuli_wdr.h" // Needed for amuleSpecial
38 BEGIN_EVENT_TABLE(CDirectoryTreeCtrl, wxTreeCtrl)
39 EVT_TREE_ITEM_RIGHT_CLICK(wxID_ANY, CDirectoryTreeCtrl::OnRButtonDown)
40 EVT_TREE_ITEM_ACTIVATED(wxID_ANY, CDirectoryTreeCtrl::OnItemActivated)
41 EVT_TREE_ITEM_EXPANDED(wxID_ANY, CDirectoryTreeCtrl::OnItemExpanding)
42 END_EVENT_TABLE()
45 class CItemData : public wxTreeItemData
47 public:
48 CItemData(const CPath& pathComponent)
49 : m_data(0)
50 , m_path(pathComponent)
54 ~CItemData() {}
56 void AddCount() { m_data++; }
57 void SubCount() { m_data--; }
58 int GetCount() const { return m_data; }
59 const CPath& GetPathComponent() const { return m_path; }
60 private:
61 int m_data;
62 CPath m_path;
66 CDirectoryTreeCtrl::CDirectoryTreeCtrl(wxWindow* parent, int id, const wxPoint& pos, wxSize siz, int flags)
67 : wxTreeCtrl(parent,id,pos,siz,flags,wxDefaultValidator,wxT("ShareTree"))
69 m_IsInit = false;
73 CDirectoryTreeCtrl::~CDirectoryTreeCtrl()
77 enum {
78 IMAGE_FOLDER = 0,
79 IMAGE_FOLDER_SUB_SHARED
83 void CDirectoryTreeCtrl::Init()
85 // already done ?
86 if (m_IsInit) {
87 return;
89 m_IsInit = true;
91 // init image(s)
92 wxImageList* images = new wxImageList(16, 16);
93 images->Add(wxBitmap(amuleSpecial(1)));
94 images->Add(wxBitmap(amuleSpecial(2)));
95 // Gives wxTreeCtrl ownership of the list
96 AssignImageList(images);
99 // Create an empty root item, which we can
100 // safely append when creating a full path.
101 wxTreeItemId root = AddRoot(wxEmptyString, IMAGE_FOLDER, -1,
102 new CItemData(CPath()));
105 #ifndef __WXMSW__
106 AddChildItem(root, CPath(wxT("/")));
107 #else
108 // this might take awhile, so change the cursor
109 ::wxSetCursor(*wxHOURGLASS_CURSOR);
110 // retrieve bitmask of all drives available
111 uint32 drives = GetLogicalDrives();
112 drives >>= 1;
113 for (char drive = 'C'; drive <= 'Z'; drive++) {
114 drives >>= 1;
115 if (! (drives & 1)) { // skip non existant drives
116 continue;
118 wxString driveStr = wxString::Format(wxT("%c:"), drive);
119 uint32 type = GetDriveType(driveStr + wxT("\\"));
121 // skip removable/undefined drives, share only fixed or remote drives
122 if ((type == 3 || type == 4) // fixed drive / remote drive
123 && CPath::DirExists(driveStr)) {
124 AddChildItem(root, CPath(driveStr));
127 ::wxSetCursor(*wxSTANDARD_CURSOR);
128 #endif
130 HasChanged = false;
132 UpdateSharedDirectories();
136 void CDirectoryTreeCtrl::OnItemExpanding(wxTreeEvent& evt)
138 wxTreeItemId hItem = evt.GetItem();
140 // Force reloading of the path
141 DeleteChildren(hItem);
142 AddSubdirectories(hItem, GetFullPath(hItem));
144 SortChildren(hItem);
148 void CDirectoryTreeCtrl::OnItemActivated(wxTreeEvent& evt)
150 CheckChanged(evt.GetItem(), !IsBold(evt.GetItem()));
151 HasChanged = true;
155 void CDirectoryTreeCtrl::OnRButtonDown(wxTreeEvent& evt)
157 MarkChildren(evt.GetItem(), !IsBold(evt.GetItem()));
158 HasChanged = true;
162 void CDirectoryTreeCtrl::MarkChildren(wxTreeItemId hChild, bool mark)
164 // Ensure that children are added, otherwise we might only get a "." entry.
165 if (!IsExpanded(hChild) && ItemHasChildren(hChild)) {
166 DeleteChildren(hChild);
167 AddSubdirectories(hChild, GetFullPath(hChild));
168 SortChildren(hChild);
171 wxTreeItemIdValue cookie;
172 wxTreeItemId hChild2 = GetFirstChild(hChild, cookie);
173 while (hChild2.IsOk()) {
174 MarkChildren(hChild2, mark);
176 hChild2 = GetNextSibling(hChild2);
179 CheckChanged(hChild, mark);
183 void CDirectoryTreeCtrl::AddChildItem(wxTreeItemId hBranch, const CPath& item)
185 wxCHECK_RET(hBranch.IsOk(), wxT("Attempted to add children to invalid item"));
187 CPath fullPath = GetFullPath(hBranch).JoinPaths(item);
188 wxTreeItemId treeItem = AppendItem(hBranch, item.GetPrintable(),
189 IMAGE_FOLDER, -1,
190 new CItemData(item));
192 if (IsShared(fullPath)) {
193 SetItemBold(treeItem, true);
194 UpdateParentItems(treeItem, true);
197 if (HasSharedSubdirectory(fullPath)) {
198 SetItemImage(treeItem, IMAGE_FOLDER_SUB_SHARED);
201 if (HasSubdirectories(fullPath)) {
202 // Trick. will show + if it has subdirs
203 AppendItem(treeItem, wxT("."));
208 CPath CDirectoryTreeCtrl::GetFullPath(wxTreeItemId hItem)
210 wxCHECK_MSG(hItem.IsOk(), CPath(), wxT("Invalid item in GetFullPath"));
212 CPath result;
213 for (; hItem.IsOk(); hItem = GetItemParent(hItem)) {
214 CItemData* data = dynamic_cast<CItemData*>(GetItemData(hItem));
215 wxCHECK_MSG(data, CPath(), wxT("Missing data-item in GetFullPath"));
217 result = data->GetPathComponent().JoinPaths(result);
220 return result;
224 void CDirectoryTreeCtrl::AddSubdirectories(wxTreeItemId hBranch, const CPath& path)
226 wxCHECK_RET(path.IsOk(), wxT("Invalid path in AddSubdirectories"));
228 CDirIterator sharedDir(path);
230 CPath dirName = sharedDir.GetFirstFile(CDirIterator::Dir);
231 while (dirName.IsOk()) {
232 AddChildItem(hBranch, dirName);
234 dirName = sharedDir.GetNextFile();
239 bool CDirectoryTreeCtrl::HasSubdirectories(const CPath& folder)
241 // Prevent error-messages if we try to traverse somewhere we have no access.
242 wxLogNull logNo;
244 return CDirIterator(folder).HasSubDirs();
248 void CDirectoryTreeCtrl::GetSharedDirectories(PathList* list)
250 wxCHECK_RET(list, wxT("Invalid list in GetSharedDirectories"));
252 list->insert(list->end(), m_lstShared.begin(), m_lstShared.end());
256 void CDirectoryTreeCtrl::SetSharedDirectories(PathList* list)
258 wxCHECK_RET(list, wxT("Invalid list in SetSharedDirectories"));
260 m_lstShared.clear();
261 m_lstShared.insert(m_lstShared.end(), list->begin(), list->end());
263 if (m_IsInit) {
264 UpdateSharedDirectories();
269 void CDirectoryTreeCtrl::UpdateSharedDirectories()
271 // Mark all shared root items (on windows this can be multiple
272 // drives, on unix there is only the root dir).
273 wxTreeItemIdValue cookie;
274 wxTreeItemId hChild = GetFirstChild(GetRootItem(), cookie);
276 while (hChild.IsOk()) {
277 // Does this drive have shared subfolders?
278 if (HasSharedSubdirectory(GetFullPath(hChild))) {
279 SetItemImage(hChild, IMAGE_FOLDER_SUB_SHARED);
282 // Is this drive shared?
283 if (IsShared(GetFullPath(hChild))) {
284 SetItemBold(hChild, true);
287 hChild = GetNextSibling(hChild);
292 bool CDirectoryTreeCtrl::HasSharedSubdirectory(const CPath& path)
294 PathList::iterator it = m_lstShared.begin();
295 for (; it != m_lstShared.end(); ++it) {
296 // IsSameDir to avoid the case where 'path' itself is shared.
297 if (it->StartsWith(path) && (!it->IsSameDir(path))) {
298 return true;
302 return false;
306 void CDirectoryTreeCtrl::CheckChanged(wxTreeItemId hItem, bool bChecked)
308 if (IsBold(hItem) != bChecked) {
309 SetItemBold(hItem, bChecked);
311 if (bChecked) {
312 AddShare(GetFullPath(hItem));
313 } else {
314 DelShare(GetFullPath(hItem));
317 UpdateParentItems(hItem, bChecked);
322 bool CDirectoryTreeCtrl::IsShared(const CPath& path)
324 wxCHECK_MSG(path.IsOk(), false, wxT("Invalid path in IsShared"));
326 PathList::iterator it = m_lstShared.begin();
327 for (; it != m_lstShared.end(); ++it) {
328 if (it->IsSameDir(path)) {
329 return true;
333 return false;
337 void CDirectoryTreeCtrl::AddShare(const CPath& path)
339 wxCHECK_RET(path.IsOk(), wxT("Invalid path in AddShare"));
341 if (IsShared(path)) {
342 return;
345 m_lstShared.push_back(path);
349 void CDirectoryTreeCtrl::DelShare(const CPath& path)
351 wxCHECK_RET(path.IsOk(), wxT("Invalid path in DelShare"));
353 PathList::iterator it = m_lstShared.begin();
354 for (; it != m_lstShared.end(); ++it ) {
355 if (it->IsSameDir(path)) {
356 m_lstShared.erase(it);
357 return;
363 void CDirectoryTreeCtrl::UpdateParentItems(wxTreeItemId hChild, bool add)
365 wxTreeItemId parent = hChild;
366 while (parent != GetRootItem()) {
367 parent = GetItemParent(parent);
368 CItemData* parent_data = dynamic_cast<CItemData*>(GetItemData(parent));
369 if (add) {
370 parent_data->AddCount();
371 if (parent_data->GetCount()==1) {
372 SetItemImage(parent, IMAGE_FOLDER_SUB_SHARED);
374 } else {
375 switch (parent_data->GetCount()) {
376 case 0:
377 break;
378 case 1:
379 SetItemImage(parent, IMAGE_FOLDER);
380 default:
381 parent_data->SubCount();
382 break;
387 // File_checked_for_headers