2 // This file is part of the aMule Project.
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 )
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.
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
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
)
45 class CItemData
: public wxTreeItemData
48 CItemData(const CPath
& pathComponent
)
50 , m_path(pathComponent
)
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
; }
66 CDirectoryTreeCtrl::CDirectoryTreeCtrl(wxWindow
* parent
, int id
, const wxPoint
& pos
, wxSize siz
, int flags
)
67 : wxTreeCtrl(parent
,id
,pos
,siz
,flags
,wxDefaultValidator
,wxT("ShareTree"))
73 CDirectoryTreeCtrl::~CDirectoryTreeCtrl()
79 IMAGE_FOLDER_SUB_SHARED
83 void CDirectoryTreeCtrl::Init()
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()));
106 AddChildItem(root
, CPath(wxT("/")));
108 // this might take awhile, so change the cursor
109 ::wxSetCursor(*wxHOURGLASS_CURSOR
);
110 // retrieve bitmask of all drives available
111 uint32 drives
= GetLogicalDrives();
113 for (char drive
= 'C'; drive
<= 'Z'; drive
++) {
115 if (! (drives
& 1)) { // skip non existant drives
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
);
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
));
148 void CDirectoryTreeCtrl::OnItemActivated(wxTreeEvent
& evt
)
150 CheckChanged(evt
.GetItem(), !IsBold(evt
.GetItem()));
155 void CDirectoryTreeCtrl::OnRButtonDown(wxTreeEvent
& evt
)
157 MarkChildren(evt
.GetItem(), !IsBold(evt
.GetItem()));
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(),
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"));
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
);
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.
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"));
261 m_lstShared
.insert(m_lstShared
.end(), list
->begin(), list
->end());
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
))) {
306 void CDirectoryTreeCtrl::CheckChanged(wxTreeItemId hItem
, bool bChecked
)
308 if (IsBold(hItem
) != bChecked
) {
309 SetItemBold(hItem
, bChecked
);
312 AddShare(GetFullPath(hItem
));
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
)) {
337 void CDirectoryTreeCtrl::AddShare(const CPath
& path
)
339 wxCHECK_RET(path
.IsOk(), wxT("Invalid path in AddShare"));
341 if (IsShared(path
)) {
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
);
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
));
370 parent_data
->AddCount();
371 if (parent_data
->GetCount()==1) {
372 SetItemImage(parent
, IMAGE_FOLDER_SUB_SHARED
);
375 switch (parent_data
->GetCount()) {
379 SetItemImage(parent
, IMAGE_FOLDER
);
381 parent_data
->SubCount();
387 // File_checked_for_headers