1 #include "FileExplorer.h"
2 #include <wx/dir.h>
3 #include <wx/filename.h>
4 #include <wx/aui/aui.h>
5 
6 #include <sdk.h>
7 #ifndef CB_PRECOMP
8     #include <wx/dnd.h>
9     #include <wx/imaglist.h>
10 
11     #include <cbproject.h>
12     #include <configmanager.h>
13     #include <projectmanager.h>
14 #endif
15 
16 #include <list>
17 #include <vector>
18 #include <iostream>
19 
20 #include "se_globals.h"
21 #include "CommitBrowser.h"
22 
23 #include <wx/arrimpl.cpp> // this is a magic incantation which must be done!
24 WX_DEFINE_OBJARRAY(VCSstatearray);
25 
26 int ID_UPDATETIMER=wxNewId();
27 int ID_FILETREE=wxNewId();
28 int ID_FILELOC=wxNewId();
29 int ID_FILEWILD=wxNewId();
30 int ID_SETLOC=wxNewId();
31 int ID_VCSCONTROL=wxNewId();
32 int ID_VCSTYPE=wxNewId();
33 int ID_VCSCHANGESCHECK = wxNewId();
34 
35 int ID_OPENINED=wxNewId();
36 int ID_FILENEWFILE=wxNewId();
37 int ID_FILENEWFOLDER=wxNewId();
38 int ID_FILEMAKEFAV=wxNewId();
39 int ID_FILECOPY=wxNewId();
40 int ID_FILEDUP=wxNewId();
41 int ID_FILEMOVE=wxNewId();
42 int ID_FILEDELETE=wxNewId();
43 int ID_FILERENAME=wxNewId();
44 int ID_FILEEXPANDALL=wxNewId();
45 int ID_FILECOLLAPSEALL=wxNewId();
46 int ID_FILESETTINGS=wxNewId();
47 int ID_FILESHOWHIDDEN=wxNewId();
48 int ID_FILEPARSECVS=wxNewId();
49 int ID_FILEPARSESVN=wxNewId();
50 int ID_FILEPARSEHG=wxNewId();
51 int ID_FILEPARSEBZR=wxNewId();
52 int ID_FILEPARSEGIT=wxNewId();
53 int ID_FILE_UPBUTTON=wxNewId();
54 int ID_FILEREFRESH=wxNewId();
55 int ID_FILEADDTOPROJECT=wxNewId();
56 
57 int ID_FILEDIFF=wxNewId();
58 // 10 additional ID's reserved for FILE DIFF items
59 int ID_FILEDIFF1=wxNewId();
60 int ID_FILEDIFF2=wxNewId();
61 int ID_FILEDIFF3=wxNewId();
62 int ID_FILEDIFF4=wxNewId();
63 int ID_FILEDIFF5=wxNewId();
64 int ID_FILEDIFF6=wxNewId();
65 int ID_FILEDIFF7=wxNewId();
66 int ID_FILEDIFF8=wxNewId();
67 int ID_FILEDIFF9=wxNewId();
68 int ID_FILEDIFF10=wxNewId();
69 //
70 
71 
72 class UpdateQueue
73 {
74 public:
Add(const wxTreeItemId & ti)75     void Add(const wxTreeItemId &ti)
76     {
77         for(std::list<wxTreeItemId>::iterator it=qdata.begin();it!=qdata.end();it++)
78         {
79             if(*it==ti)
80             {
81                 qdata.erase(it);
82                 break;
83             }
84         }
85         qdata.push_front(ti);
86     }
Pop(wxTreeItemId & ti)87     bool Pop(wxTreeItemId &ti)
88     {
89         if(qdata.empty())
90             return false;
91         ti=qdata.front();
92         qdata.pop_front();
93         return true;
94     }
Clear()95     void Clear()
96     {
97         qdata.clear();
98     }
99 private:
100     std::list<wxTreeItemId> qdata;
101 };
102 
103 
104 class DirTraverseFind : public wxDirTraverser     {
105 public:
DirTraverseFind(const wxString & wildcard)106     DirTraverseFind(const wxString& wildcard) : m_files(), m_wildcard(wildcard) { }
OnFile(const wxString & filename)107     virtual wxDirTraverseResult OnFile(const wxString& filename)
108     {
109         if(WildCardListMatch(m_wildcard,filename,true))
110             m_files.Add(filename);
111         return wxDIR_CONTINUE;
112     }
OnDir(const wxString & dirname)113     virtual wxDirTraverseResult OnDir(const wxString& dirname)
114     {
115         if(WildCardListMatch(m_wildcard,dirname,true))
116             m_files.Add(dirname);
117         return wxDIR_CONTINUE;
118     }
GetMatches()119     wxArrayString& GetMatches() {return m_files;}
120 private:
121     wxArrayString m_files;
122     wxString m_wildcard;
123 };
124 
125 
126 class FEDataObject:public wxDataObjectComposite
127 {
128 public:
FEDataObject()129    FEDataObject():wxDataObjectComposite()
130    {
131        m_file=new wxFileDataObject;
132        Add(m_file,true);
133    }
134    wxFileDataObject *m_file;
135 
136 };
137 
138 
139 class wxFEDropTarget: public wxDropTarget
140 {
141 public:
wxFEDropTarget(FileExplorer * fe)142     wxFEDropTarget(FileExplorer *fe):wxDropTarget()
143     {
144         m_fe=fe;
145         m_data_object=new FEDataObject();
146         SetDataObject(m_data_object);
147     }
OnData(wxCoord x,wxCoord y,wxDragResult def)148     virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
149     {
150         GetData();
151         if(m_data_object->GetReceivedFormat().GetType()==wxDF_FILENAME )
152         {
153             wxArrayString as=m_data_object->m_file->GetFilenames();
154             wxTreeCtrl *tree=m_fe->m_Tree;
155             int flags;
156             wxTreeItemId id=tree->HitTest(wxPoint(x,y),flags);
157             if(!id.IsOk())
158                 return wxDragCancel;
159             if(tree->GetItemImage(id)!=fvsFolder)
160                 return wxDragCancel;
161             if(!(flags&(wxTREE_HITTEST_ONITEMICON|wxTREE_HITTEST_ONITEMLABEL)))
162                 return wxDragCancel;
163             if(def==wxDragCopy)
164             {
165                 m_fe->CopyFiles(m_fe->GetFullPath(id),as);
166                 return def;
167             }
168             if(def==wxDragMove)
169             {
170                 m_fe->MoveFiles(m_fe->GetFullPath(id),as);
171                 return def;
172             }
173             return wxDragCancel;
174         }
175 //            if(sizeof(wxFileDataObject)!=m_data_object->GetDataSize(wxDF_FILENAME))
176 //            {
177 //                wxMessageBox(wxString::Format(_("Drop files %i,%i"),sizeof(wxFileDataObject),m_data_object->GetDataSize(wxDF_FILENAME)));
178 //                return wxDragCancel;
179 //            }
180         return wxDragCancel;
181     }
OnDrop(wxCoord,wxCoord,int,wxWindow *)182     virtual bool OnDrop(wxCoord /*x*/, wxCoord /*y*/, int /*tab*/, wxWindow */*wnd*/)
183     {
184         return true;
185     }
OnDragOver(wxCoord,wxCoord,wxDragResult def)186     virtual wxDragResult OnDragOver(wxCoord /*x*/, wxCoord /*y*/, wxDragResult def)
187     {
188         return def;
189     }
190 private:
191     FEDataObject *m_data_object;
192     FileExplorer *m_fe;
193 };
194 
195 
196 
BEGIN_EVENT_TABLE(FileTreeCtrl,wxTreeCtrl)197 BEGIN_EVENT_TABLE(FileTreeCtrl, wxTreeCtrl)
198 //    EVT_TREE_ITEM_ACTIVATED(ID_FILETREE, FileTreeCtrl::OnActivate)  //double click -
199     EVT_KEY_DOWN(FileTreeCtrl::OnKeyDown)
200 END_EVENT_TABLE()
201 
202 IMPLEMENT_DYNAMIC_CLASS(FileTreeCtrl, wxTreeCtrl)
203 
204 FileTreeCtrl::FileTreeCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos,
205     const wxSize& size, long style,
206     const wxValidator& validator,
207     const wxString& name)
208     : wxTreeCtrl(parent,id,pos,size,style,validator,name) {}
209 
FileTreeCtrl()210 FileTreeCtrl::FileTreeCtrl() { }
211 
FileTreeCtrl(wxWindow * parent)212 FileTreeCtrl::FileTreeCtrl(wxWindow *parent): wxTreeCtrl(parent) {}
213 
~FileTreeCtrl()214 FileTreeCtrl::~FileTreeCtrl()
215 {
216 }
217 
OnKeyDown(wxKeyEvent & event)218 void FileTreeCtrl::OnKeyDown(wxKeyEvent &event)
219 {
220     if(event.GetKeyCode()==WXK_DELETE)
221         ::wxPostEvent(GetParent(),event);
222     else
223         event.Skip(true);
224 }
225 
OnCompareItems(const wxTreeItemId & item1,const wxTreeItemId & item2)226 int FileTreeCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)
227 {
228     if((GetItemImage(item1)==fvsFolder)>(GetItemImage(item2)==fvsFolder))
229         return -1;
230     if((GetItemImage(item1)==fvsFolder)<(GetItemImage(item2)==fvsFolder))
231         return 1;
232     if((GetItemImage(item1)==fvsVcNonControlled)<(GetItemImage(item2)==fvsVcNonControlled))
233         return -1;
234     if((GetItemImage(item1)==fvsVcNonControlled)<(GetItemImage(item2)==fvsVcNonControlled))
235         return 1;
236     return (GetItemText(item1).CmpNoCase(GetItemText(item2)));
237 }
238 
BEGIN_EVENT_TABLE(FileExplorer,wxPanel)239 BEGIN_EVENT_TABLE(FileExplorer, wxPanel)
240     EVT_TIMER(ID_UPDATETIMER, FileExplorer::OnTimerCheckUpdates)
241     EVT_MONITOR_NOTIFY(wxID_ANY, FileExplorer::OnDirMonitor)
242     EVT_COMMAND(0, wxEVT_NOTIFY_UPDATE_COMPLETE, FileExplorer::OnUpdateTreeItems)
243     EVT_COMMAND(0, wxEVT_NOTIFY_LOADER_UPDATE_COMPLETE, FileExplorer::OnVCSFileLoaderComplete)
244 //    EVT_COMMAND(0, wxEVT_NOTIFY_EXEC_REQUEST, FileExplorer::OnExecRequest)
245     EVT_TREE_BEGIN_DRAG(ID_FILETREE, FileExplorer::OnBeginDragTreeItem)
246     EVT_TREE_END_DRAG(ID_FILETREE, FileExplorer::OnEndDragTreeItem)
247     EVT_BUTTON(ID_FILE_UPBUTTON, FileExplorer::OnUpButton)
248     EVT_MENU(ID_SETLOC, FileExplorer::OnSetLoc)
249     EVT_MENU(ID_OPENINED, FileExplorer::OnOpenInEditor)
250     EVT_MENU(ID_FILENEWFILE, FileExplorer::OnNewFile)
251     EVT_MENU(ID_FILENEWFOLDER,FileExplorer::OnNewFolder)
252     EVT_MENU(ID_FILEMAKEFAV,FileExplorer::OnAddFavorite)
253     EVT_MENU(ID_FILECOPY,FileExplorer::OnCopy)
254     EVT_MENU(ID_FILEDUP,FileExplorer::OnDuplicate)
255     EVT_MENU(ID_FILEMOVE,FileExplorer::OnMove)
256     EVT_MENU(ID_FILEDELETE,FileExplorer::OnDelete)
257     EVT_MENU(ID_FILERENAME,FileExplorer::OnRename)
258     EVT_MENU(ID_FILEEXPANDALL,FileExplorer::OnExpandAll)
259     EVT_MENU(ID_FILECOLLAPSEALL,FileExplorer::OnCollapseAll)
260     EVT_MENU(ID_FILESETTINGS,FileExplorer::OnSettings)
261     EVT_MENU(ID_FILESHOWHIDDEN,FileExplorer::OnShowHidden)
262     EVT_MENU(ID_FILEPARSECVS,FileExplorer::OnParseCVS)
263     EVT_MENU(ID_FILEPARSESVN,FileExplorer::OnParseSVN)
264     EVT_MENU(ID_FILEPARSEHG,FileExplorer::OnParseHG)
265     EVT_MENU(ID_FILEPARSEBZR,FileExplorer::OnParseBZR)
266     EVT_MENU(ID_FILEPARSEGIT,FileExplorer::OnParseGIT)
267     EVT_MENU(ID_FILEREFRESH,FileExplorer::OnRefresh)
268     EVT_MENU(ID_FILEADDTOPROJECT,FileExplorer::OnAddToProject)
269     EVT_MENU_RANGE(ID_FILEDIFF, ID_FILEDIFF+10, FileExplorer::OnVCSDiff)
270     EVT_KEY_DOWN(FileExplorer::OnKeyDown)
271     EVT_TREE_ITEM_EXPANDING(ID_FILETREE, FileExplorer::OnExpand)
272     //EVT_TREE_ITEM_COLLAPSED(id, func) //delete the children
273     EVT_TREE_ITEM_ACTIVATED(ID_FILETREE, FileExplorer::OnActivate)  //double click - open file / expand folder (the latter is a default just need event.skip)
274     EVT_TREE_ITEM_MENU(ID_FILETREE, FileExplorer::OnRightClick) //right click open context menu -- interpreter actions, rename, delete, copy, properties, set as root etc
275     EVT_COMBOBOX(ID_FILELOC, FileExplorer::OnChooseLoc) //location selected from history of combo box - set as root
276     EVT_COMBOBOX(ID_FILEWILD, FileExplorer::OnChooseWild) //location selected from history of combo box - set as root
277     //EVT_TEXT(ID_FILELOC, FileExplorer::OnLocChanging) //provide autotext hint for dir name in combo box
278     EVT_TEXT_ENTER(ID_FILELOC, FileExplorer::OnEnterLoc) //location entered in combo box - set as root
279     EVT_TEXT_ENTER(ID_FILEWILD, FileExplorer::OnEnterWild) //location entered in combo box - set as root  ** BUG RIDDEN
280     EVT_CHOICE(ID_VCSCONTROL, FileExplorer::OnVCSControl)
281     EVT_CHECKBOX(ID_VCSCHANGESCHECK, FileExplorer::OnVCSChangesCheck)
282 END_EVENT_TABLE()
283 
284 FileExplorer::FileExplorer(wxWindow *parent,wxWindowID id,
285     const wxPoint& pos, const wxSize& size,
286     long style, const wxString& name):
287     wxPanel(parent,id,pos,size,style, name)
288 {
289     m_kill=false;
290     m_update_queue=new UpdateQueue;
291     m_updater=NULL;
292     m_updatetimer=new wxTimer(this,ID_UPDATETIMER);
293     m_update_active=false;
294     m_updater_cancel=false;
295     m_update_expand=false;
296     m_dir_monitor=new wxDirectoryMonitor(this,wxArrayString());
297     m_dir_monitor->Start();
298     m_droptarget=new wxFEDropTarget(this);
299 
300     m_show_hidden=false;
301     m_parse_cvs=false;
302     m_parse_hg=false;
303     m_parse_bzr=false;
304     m_parse_git=false;
305     m_parse_svn=false;
306     m_vcs_file_loader=0;
307     wxBoxSizer* bs = new wxBoxSizer(wxVERTICAL);
308     wxBoxSizer* bsh = new wxBoxSizer(wxHORIZONTAL);
309     wxBoxSizer* bshloc = new wxBoxSizer(wxHORIZONTAL);
310     m_Box_VCS_Control = new wxBoxSizer(wxVERTICAL);
311     wxBoxSizer *box_vcs_top = new wxBoxSizer(wxHORIZONTAL);
312     m_Tree = new FileTreeCtrl(this, ID_FILETREE);
313     m_Tree->SetIndent(m_Tree->GetIndent()/2);
314     m_Tree->SetDropTarget(m_droptarget);
315     m_Loc = new wxComboBox(this,ID_FILELOC,_T(""),wxDefaultPosition,wxDefaultSize,0,NULL,wxTE_PROCESS_ENTER|wxCB_DROPDOWN);
316     m_WildCards = new wxComboBox(this,ID_FILEWILD,_T(""),wxDefaultPosition,wxDefaultSize,0,NULL,wxTE_PROCESS_ENTER|wxCB_DROPDOWN);
317     m_UpButton = new wxButton(this,ID_FILE_UPBUTTON,_("^"),wxDefaultPosition,wxDefaultSize,wxBU_EXACTFIT);
318     bshloc->Add(m_Loc, 1, wxEXPAND);
319     bshloc->Add(m_UpButton, 0, wxEXPAND);
320     bs->Add(bshloc, 0, wxEXPAND);
321     bsh->Add(new wxStaticText(this,wxID_ANY,_("Mask: ")),0,wxALIGN_CENTRE);
322     bsh->Add(m_WildCards,1);
323     bs->Add(bsh, 0, wxEXPAND);
324 
325     m_VCS_Control = new wxChoice(this,ID_VCSCONTROL);
326     m_VCS_Type = new wxStaticText(this,ID_VCSTYPE,_T(""));
327     m_VCS_ChangesOnly = new wxCheckBox(this, ID_VCSCHANGESCHECK, _T("Show changed files only"));
328     box_vcs_top->Add(m_VCS_Type,0,wxALIGN_CENTER);
329     box_vcs_top->Add(m_VCS_Control,1,wxEXPAND);
330     m_Box_VCS_Control->Add(box_vcs_top, 0, wxEXPAND);
331     m_Box_VCS_Control->Add(m_VCS_ChangesOnly, 0, wxEXPAND);
332     m_Box_VCS_Control->Hide(true);
333     bs->Add(m_Box_VCS_Control, 0, wxEXPAND);
334 
335     bs->Add(m_Tree, 1, wxEXPAND | wxALL);
336 
337     SetAutoLayout(TRUE);
338 
339     m_TreeImages = cbProjectTreeImages::MakeImageList(16, *this);
340     m_Tree->SetImageList(m_TreeImages.get());
341 
342     ReadConfig();
343     if(m_Loc->GetCount()>m_favdirs.GetCount())
344     {
345         m_Loc->Select(m_favdirs.GetCount());
346         m_root=m_Loc->GetString(m_favdirs.GetCount());
347     } else
348     {
349         m_root=wxFileName::GetPathSeparator();
350         m_Loc->Append(m_root);
351         m_Loc->Select(0);
352     }
353     if(m_WildCards->GetCount()>0)
354         m_WildCards->Select(0);
355     SetRootFolder(m_root);
356 
357     SetSizer(bs);
358 }
359 
~FileExplorer()360 FileExplorer::~FileExplorer()
361 {
362     m_kill=true;
363     m_updatetimer->Stop();
364     delete m_dir_monitor;
365     WriteConfig();
366     UpdateAbort();
367     delete m_update_queue;
368     delete m_updatetimer;
369 }
370 
371 
SetRootFolder(wxString root)372 bool FileExplorer::SetRootFolder(wxString root)
373 {
374     UpdateAbort();
375     if(root[root.Len()-1]!=wxFileName::GetPathSeparator())
376         root=root+wxFileName::GetPathSeparator();
377 #ifdef __WXMSW__
378     wxFileName fnroot=wxFileName(root);
379     if(fnroot.GetVolume().IsEmpty())
380     {
381         fnroot.SetVolume(wxFileName(::wxGetCwd()).GetVolume());
382         root=fnroot.GetFullPath();//(wxPATH_GET_VOLUME|wxPATH_GET_SEPARATOR)+fnroot.GetFullName();
383     }
384 #endif
385     wxDir dir(root);
386     if (!dir.IsOpened())
387     {
388         // deal with the error here - wxDir would already log an error message
389         // explaining the exact reason of the failure
390         m_Loc->SetValue(m_root);
391         return false;
392     }
393     m_root=root;
394     m_VCS_Control->Clear();
395     m_commit = wxEmptyString;
396     m_VCS_Type->SetLabel(wxEmptyString);
397     m_Box_VCS_Control->Hide(true);
398     m_Loc->SetValue(m_root);
399     m_Tree->DeleteAllItems();
400     m_Tree->AddRoot(m_root,fvsFolder);
401     m_Tree->SetItemHasChildren(m_Tree->GetRootItem());
402     m_Tree->Expand(m_Tree->GetRootItem());
403     Layout();
404 
405     return true;
406 //    return AddTreeItems(m_Tree->GetRootItem());
407 
408 }
409 
410 // find a file in the filesystem below a selected root
FindFile(const wxString & findfilename,const wxTreeItemId & ti)411 void FileExplorer::FindFile(const wxString &findfilename, const wxTreeItemId &ti)
412 {
413     wxString path=GetFullPath(ti);
414 
415     wxDir dir(path);
416 
417     if (!dir.IsOpened())
418     {
419         // deal with the error here - wxDir would already log an error message
420         // explaining the exact reason for the failure
421         return;
422     }
423     wxString filename;
424     int flags=wxDIR_FILES|wxDIR_DIRS;
425     if(m_show_hidden)
426         flags|=wxDIR_HIDDEN;
427 
428     DirTraverseFind dtf(findfilename);
429     m_findmatchcount=dir.Traverse(dtf,wxEmptyString,flags);
430     m_findmatch=dtf.GetMatches();
431 }
432 
433 // focus the item in the tree.
FocusFile(const wxTreeItemId & ti)434 void FileExplorer::FocusFile(const wxTreeItemId &ti)
435 {
436     m_Tree->SetFocus();
437     m_Tree->UnselectAll();
438     m_Tree->SelectItem(ti);
439     m_Tree->EnsureVisible(ti);
440 }
441 
GetNextExpandedNode(wxTreeItemId ti)442 wxTreeItemId FileExplorer::GetNextExpandedNode(wxTreeItemId ti)
443 {
444     wxTreeItemId next_ti;
445     if(!ti.IsOk())
446     {
447         return m_Tree->GetRootItem();
448     }
449     if(m_Tree->IsExpanded(ti))
450     {
451         wxTreeItemIdValue cookie;
452         next_ti=m_Tree->GetFirstChild(ti,cookie);
453         while(next_ti.IsOk())
454         {
455             if(m_Tree->IsExpanded(next_ti))
456                 return next_ti;
457             next_ti=m_Tree->GetNextChild(ti,cookie);
458         }
459     }
460     next_ti=m_Tree->GetNextSibling(ti);
461     while(next_ti.IsOk())
462     {
463         if(m_Tree->IsExpanded(next_ti))
464             return next_ti;
465         next_ti=m_Tree->GetNextSibling(next_ti);
466     }
467     return m_Tree->GetRootItem();
468 }
469 
GetItemFromPath(const wxString & path,wxTreeItemId & ti)470 bool FileExplorer::GetItemFromPath(const wxString &path, wxTreeItemId &ti)
471 {
472     ti=m_Tree->GetRootItem();
473     do
474     {
475         if(path==GetFullPath(ti))
476             return true;
477         ti=GetNextExpandedNode(ti);
478     } while(ti!=m_Tree->GetRootItem());
479     return false;
480 }
481 
482 
GetExpandedNodes(wxTreeItemId ti,Expansion * exp)483 void FileExplorer::GetExpandedNodes(wxTreeItemId ti, Expansion *exp)
484 {
485     exp->name=m_Tree->GetItemText(ti);
486     wxTreeItemIdValue cookie;
487     wxTreeItemId ch=m_Tree->GetFirstChild(ti,cookie);
488     while(ch.IsOk())
489     {
490         if(m_Tree->IsExpanded(ch))
491         {
492             Expansion *e=new Expansion();
493             GetExpandedNodes(ch,e);
494             exp->children.push_back(e);
495         }
496         ch=m_Tree->GetNextChild(ti,cookie);
497     }
498 }
499 
GetExpandedPaths(wxTreeItemId ti,wxArrayString & paths)500 void FileExplorer::GetExpandedPaths(wxTreeItemId ti,wxArrayString &paths)
501 {
502     if(!ti.IsOk())
503     {
504         wxMessageBox(_("node error"));
505         return;
506     }
507     if(m_Tree->IsExpanded(ti))
508         paths.Add(GetFullPath(ti));
509     wxTreeItemIdValue cookie;
510     wxTreeItemId ch=m_Tree->GetFirstChild(ti,cookie);
511     while(ch.IsOk())
512     {
513         if(m_Tree->IsExpanded(ch))
514             GetExpandedPaths(ch,paths);
515         ch=m_Tree->GetNextChild(ti,cookie);
516     }
517 }
518 
RefreshExpanded(wxTreeItemId ti)519 void FileExplorer::RefreshExpanded(wxTreeItemId ti)
520 {
521     if(m_Tree->IsExpanded(ti))
522         m_update_queue->Add(ti);
523     wxTreeItemIdValue cookie;
524     wxTreeItemId ch=m_Tree->GetFirstChild(ti,cookie);
525     while(ch.IsOk())
526     {
527         if(m_Tree->IsExpanded(ch))
528             RefreshExpanded(ch);
529         ch=m_Tree->GetNextChild(ti,cookie);
530     }
531     m_updatetimer->Start(10,true);
532 
533 }
534 
Refresh(wxTreeItemId ti)535 void FileExplorer::Refresh(wxTreeItemId ti)
536 {
537     //    Expansion e;
538     //    GetExpandedNodes(ti,&e);
539     //    RecursiveRebuild(ti,&e);
540     //m_updating_node=ti;//m_Tree->GetRootItem();
541     m_update_queue->Add(ti);
542     m_updatetimer->Start(10,true);
543 }
544 
UpdateAbort()545 void FileExplorer::UpdateAbort()
546 {
547     if(!m_update_active)
548         return;
549     delete m_updater;
550     m_update_active=false;
551     m_updatetimer->Stop();
552 }
553 
ResetDirMonitor()554 void FileExplorer::ResetDirMonitor()
555 {
556     wxArrayString paths;
557     GetExpandedPaths(m_Tree->GetRootItem(),paths);
558     m_dir_monitor->ChangePaths(paths);
559 }
560 
OnDirMonitor(wxDirectoryMonitorEvent & e)561 void FileExplorer::OnDirMonitor(wxDirectoryMonitorEvent &e)
562 {
563     if(m_kill)
564         return;
565 //  TODO: Apparently creating log messages during Code::Blocks shutdown can create segfaults
566 //    LogMessage(wxString::Format(_T("Dir Event: %s,%i,%s"),e.m_mon_dir.c_str(),e.m_event_type,e.m_info_uri.c_str()));
567     if(e.m_event_type==MONITOR_TOO_MANY_CHANGES)
568     {
569 //        LogMessage(_("directory change read error"));
570     }
571     wxTreeItemId ti;
572     if(GetItemFromPath(e.m_mon_dir,ti))
573     {
574         m_update_queue->Add(ti);
575         m_updatetimer->Start(100,true);
576     }
577 }
578 
OnTimerCheckUpdates(wxTimerEvent &)579 void FileExplorer::OnTimerCheckUpdates(wxTimerEvent &/*e*/)
580 {
581     if(m_kill)
582         return;
583     if(m_update_active)
584         return;
585     wxTreeItemId ti;
586     while(m_update_queue->Pop(ti))
587     {
588         if(!ti.IsOk())
589             continue;
590         m_updater_cancel=false;
591         m_updater=new FileExplorerUpdater(this);
592         m_updated_node=ti;
593         m_update_active=true;
594         m_updater->Update(m_updated_node);
595         break;
596     }
597 }
598 
ValidateRoot()599 bool FileExplorer::ValidateRoot()
600 {
601     wxTreeItemId ti=m_Tree->GetRootItem();
602     while(true)
603     {
604     if(!ti.IsOk())
605         break;
606     if(m_Tree->GetItemImage(ti)!=fvsFolder)
607         break;
608     if(!wxFileName::DirExists(GetFullPath(ti)))
609         break;
610     return true;
611     }
612     return false;
613 }
614 
OnUpdateTreeItems(wxCommandEvent &)615 void FileExplorer::OnUpdateTreeItems(wxCommandEvent &/*e*/)
616 {
617     if(m_kill)
618         return;
619     m_updater->Wait();
620     wxTreeItemId ti=m_updated_node;
621     bool viewing_commit = (m_updater->m_vcs_commit_string != wxEmptyString) &&
622                           (m_updater->m_vcs_commit_string != _T("Working copy"));
623     if (ti == m_Tree->GetRootItem() && !viewing_commit)
624     {
625         m_VCS_Type->SetLabel(m_updater->m_vcs_type);
626         if (m_updater->m_vcs_type == wxEmptyString)
627         {
628             m_VCS_Control->Clear();
629             m_Box_VCS_Control->Hide(true);
630             m_commit = _T("");
631         }
632         else if (m_commit == wxEmptyString)
633         {
634             m_VCS_Control->Clear();
635             m_VCS_Control->Append(_T("Working copy"));
636             m_VCS_Control->Append(_T("Select commit..."));
637             m_VCS_Control->SetSelection(0);
638             m_commit = _T("Working copy");
639             m_Box_VCS_Control->Show(true);
640         }
641         Layout();
642     }
643     if(m_updater_cancel || !ti.IsOk())
644     { //NODE WAS DELETED - REFRESH NOW!
645         //TODO: Should only need to clean up and restart the timer (no need to change queue)
646         delete m_updater;
647         m_updater=NULL;
648         m_update_active=false;
649         ResetDirMonitor();
650         if(ValidateRoot())
651         {
652             m_update_queue->Add(m_Tree->GetRootItem());
653             m_updatetimer->Start(10,true);
654         }
655         return;
656     }
657 //    cbMessageBox(_T("Node OK"));
658 //    m_Tree->DeleteChildren(ti);
659     FileDataVec &removers=m_updater->m_removers;
660     FileDataVec &adders=m_updater->m_adders;
661     if(removers.size()>0||adders.size()>0)
662     {
663         m_Tree->Freeze();
664         //LOOP THROUGH THE REMOVERS LIST AND REMOVE THOSE ITEMS FROM THE TREE
665     //    cbMessageBox(_T("Removers"));
666         for(FileDataVec::iterator it=removers.begin();it!=removers.end();it++)
667         {
668     //        cbMessageBox(it->name);
669             wxTreeItemIdValue cookie;
670             wxTreeItemId ch=m_Tree->GetFirstChild(ti,cookie);
671             while(ch.IsOk())
672             {
673                 if(it->name==m_Tree->GetItemText(ch))
674                 {
675                     m_Tree->Delete(ch);
676                     break;
677                 }
678                 ch=m_Tree->GetNextChild(ti,cookie);
679             }
680         }
681         //LOOP THROUGH THE ADDERS LIST AND ADD THOSE ITEMS TO THE TREE
682     //    cbMessageBox(_T("Adders"));
683         for(FileDataVec::iterator it=adders.begin();it!=adders.end();it++)
684         {
685     //        cbMessageBox(it->name);
686             wxTreeItemId newitem=m_Tree->AppendItem(ti,it->name,it->state);
687             m_Tree->SetItemHasChildren(newitem,it->state==fvsFolder);
688         }
689         m_Tree->SortChildren(ti);
690         m_Tree->Thaw();
691     }
692     if(!m_Tree->IsExpanded(ti))
693     {
694         m_update_expand=true;
695         m_Tree->Expand(ti);
696     }
697     delete m_updater;
698     m_updater=NULL;
699     m_update_active=false;
700     m_updatetimer->Start(10,true);
701     // Restart the monitor (TODO: move this elsewhere??)
702     ResetDirMonitor();
703 }
704 
GetFullPath(const wxTreeItemId & ti)705 wxString FileExplorer::GetFullPath(const wxTreeItemId &ti)
706 {
707     if (!ti.IsOk())
708         return wxEmptyString;
709     wxFileName path(m_root);
710     if (ti!=m_Tree->GetRootItem())
711     {
712         std::vector<wxTreeItemId> vti;
713         vti.push_back(ti);
714         wxTreeItemId pti=m_Tree->GetItemParent(vti[0]);
715         if (!pti.IsOk())
716             return wxEmptyString;
717         while (pti != m_Tree->GetRootItem())
718         {
719             vti.insert(vti.begin(), pti);
720             pti=m_Tree->GetItemParent(pti);
721         }
722         //Complicated logic to deal with the fact that the selected item might
723         //be a partial path and not just a filename. It would be far simpler to
724         for (size_t i=0; i<vti.size() - 1; i++)
725             path.AppendDir(m_Tree->GetItemText(vti[i]));
726         wxFileName last_part(m_Tree->GetItemText(vti[vti.size()-1]));
727         wxArrayString as = last_part.GetDirs();
728         for (size_t i=0;i<as.size();i++)
729             path.AppendDir(as[i]);
730         path = wxFileName(path.GetFullPath(), last_part.GetFullName()).GetFullPath();
731     }
732     return path.GetFullPath();
733 }
734 
OnExpand(wxTreeEvent & event)735 void FileExplorer::OnExpand(wxTreeEvent &event)
736 {
737     if(m_updated_node==event.GetItem() && m_update_expand)
738     {
739         m_update_expand=false;
740         return;
741     }
742     m_update_queue->Add(event.GetItem());
743     m_updatetimer->Start(10,true);
744     event.Veto();
745     //AddTreeItems(event.GetItem());
746 }
747 
ReadConfig()748 void FileExplorer::ReadConfig()
749 {
750     //IMPORT SETTINGS FROM LEGACY SHELLEXTENSIONS PLUGIN - TODO: REMOVE IN NEXT VERSION
751     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("ShellExtensions"));
752     if(!cfg->Exists(_("FileExplorer/ShowHidenFiles")))
753         cfg = Manager::Get()->GetConfigManager(_T("FileManager"));
754     int len=0;
755     cfg->Read(_T("FileExplorer/FavRootList/Len"), &len);
756     for(int i=0;i<len;i++)
757     {
758         wxString ref=wxString::Format(_T("FileExplorer/FavRootList/I%i"),i);
759         wxString loc;
760         FavoriteDir fav;
761         cfg->Read(ref+_T("/alias"), &fav.alias);
762         cfg->Read(ref+_T("/path"), &fav.path);
763         m_Loc->Append(fav.alias);
764         m_favdirs.Add(fav);
765     }
766     len=0;
767     cfg->Read(_T("FileExplorer/RootList/Len"), &len);
768     for(int i=0;i<len;i++)
769     {
770         wxString ref=wxString::Format(_T("FileExplorer/RootList/I%i"),i);
771         wxString loc;
772         cfg->Read(ref, &loc);
773         m_Loc->Append(loc);
774     }
775     len=0;
776     cfg->Read(_T("FileExplorer/WildMask/Len"), &len);
777     for(int i=0;i<len;i++)
778     {
779         wxString ref=wxString::Format(_T("FileExplorer/WildMask/I%i"),i);
780         wxString wild;
781         cfg->Read(ref, &wild);
782         m_WildCards->Append(wild);
783     }
784     cfg->Read(_T("FileExplorer/ParseCVS"), &m_parse_cvs);
785     cfg->Read(_T("FileExplorer/ParseSVN"), &m_parse_svn);
786     cfg->Read(_T("FileExplorer/ParseHG"), &m_parse_hg);
787     cfg->Read(_T("FileExplorer/ParseBZR"), &m_parse_bzr);
788     cfg->Read(_T("FileExplorer/ParseGIT"), &m_parse_git);
789     cfg->Read(_T("FileExplorer/ShowHiddenFiles"), &m_show_hidden);
790 }
791 
WriteConfig()792 void FileExplorer::WriteConfig()
793 {
794     //DISCARD SETTINGS FROM LEGACY SHELLEXTENSIONS PLUGIN - TODO: REMOVE IN NEXT VERSION
795     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("ShellExtensions"));
796     if(cfg->Exists(_("FileExplorer/ShowHidenFiles")))
797         cfg->DeleteSubPath(_("FileExplorer"));
798     cfg = Manager::Get()->GetConfigManager(_T("FileManager"));
799     //cfg->Clear();
800     int count=static_cast<int>(m_favdirs.GetCount());
801     cfg->Write(_T("FileExplorer/FavRootList/Len"), count);
802     for(int i=0;i<count;i++)
803     {
804         wxString ref=wxString::Format(_T("FileExplorer/FavRootList/I%i"),i);
805         cfg->Write(ref+_T("/alias"), m_favdirs[i].alias);
806         cfg->Write(ref+_T("/path"), m_favdirs[i].path);
807     }
808     count=static_cast<int>(m_Loc->GetCount())-static_cast<int>(m_favdirs.GetCount());
809     cfg->Write(_T("FileExplorer/RootList/Len"), count);
810     for(int i=0;i<count;i++)
811     {
812         wxString ref=wxString::Format(_T("FileExplorer/RootList/I%i"),i);
813         cfg->Write(ref, m_Loc->GetString(m_favdirs.GetCount()+i));
814     }
815     count=static_cast<int>(m_Loc->GetCount());
816     cfg->Write(_T("FileExplorer/WildMask/Len"), count);
817     for(int i=0;i<count;i++)
818     {
819         wxString ref=wxString::Format(_T("FileExplorer/WildMask/I%i"),i);
820         cfg->Write(ref, m_WildCards->GetString(i));
821     }
822     cfg->Write(_T("FileExplorer/ParseCVS"), m_parse_cvs);
823     cfg->Write(_T("FileExplorer/ParseSVN"), m_parse_svn);
824     cfg->Write(_T("FileExplorer/ParseHG"), m_parse_hg);
825     cfg->Write(_T("FileExplorer/ParseBZR"), m_parse_bzr);
826     cfg->Write(_T("FileExplorer/ParseGIT"), m_parse_git);
827     cfg->Write(_T("FileExplorer/ShowHiddenFiles"), m_show_hidden);
828 }
829 
OnEnterWild(wxCommandEvent &)830 void FileExplorer::OnEnterWild(wxCommandEvent &/*event*/)
831 {
832     wxString wild=m_WildCards->GetValue();
833     for(size_t i=0;i<m_WildCards->GetCount();i++)
834     {
835         wxString cmp;
836         cmp=m_WildCards->GetString(i);
837         if(cmp==wild)
838         {
839             m_WildCards->Delete(i);
840             m_WildCards->Insert(wild,0);
841             m_WildCards->SetSelection(0);
842             RefreshExpanded(m_Tree->GetRootItem());
843             return;
844         }
845     }
846     m_WildCards->Insert(wild,0);
847     if(m_WildCards->GetCount()>10)
848         m_WildCards->Delete(10);
849     m_WildCards->SetSelection(0);
850     RefreshExpanded(m_Tree->GetRootItem());
851 }
852 
OnChooseWild(wxCommandEvent &)853 void FileExplorer::OnChooseWild(wxCommandEvent &/*event*/)
854 {
855     // Beware on win32 that if user opens drop down, then types a wildcard the combo box
856     // event will contain a -1 selection and an empty string item. Harmless in current code.
857     wxString wild=m_WildCards->GetValue();
858     m_WildCards->Delete(m_WildCards->GetSelection());
859     m_WildCards->Insert(wild,0);
860 //    event.Skip(true);
861 //    cbMessageBox(wild);
862     m_WildCards->SetSelection(0);
863     RefreshExpanded(m_Tree->GetRootItem());
864 }
865 
OnEnterLoc(wxCommandEvent &)866 void FileExplorer::OnEnterLoc(wxCommandEvent &/*event*/)
867 {
868     wxString loc=m_Loc->GetValue();
869     if(!SetRootFolder(loc))
870         return;
871     for(size_t i=0;i<m_Loc->GetCount();i++)
872     {
873         wxString cmp;
874         if(i<m_favdirs.GetCount())
875             cmp=m_favdirs[i].path;
876         else
877             cmp=m_Loc->GetString(i);
878         if(cmp==m_root)
879         {
880             if(i>=m_favdirs.GetCount())
881             {
882                 m_Loc->Delete(i);
883                 m_Loc->Insert(m_root,m_favdirs.GetCount());
884             }
885             m_Loc->SetSelection(m_favdirs.GetCount());
886             return;
887         }
888     }
889     m_Loc->Insert(m_root,m_favdirs.GetCount());
890     if(m_Loc->GetCount()>10+m_favdirs.GetCount())
891         m_Loc->Delete(10+m_favdirs.GetCount());
892     m_Loc->SetSelection(m_favdirs.GetCount());
893 }
894 
OnChooseLoc(wxCommandEvent & event)895 void FileExplorer::OnChooseLoc(wxCommandEvent &event)
896 {
897     wxString loc;
898     // on WIN32 if the user opens the drop down, but then types a path instead, this event
899     // fires with an empty string, so we have no choice but to return null. This event
900     // doesn't happen on Linux (the drop down closes when the user starts typing)
901     if(event.GetInt()<0)
902         return;
903     if(event.GetInt()>=static_cast<int>(m_favdirs.GetCount()))
904         loc=m_Loc->GetValue();
905     else
906         loc=m_favdirs[event.GetInt()].path;
907     if(!SetRootFolder(loc))
908         return;
909     if(event.GetInt()>=static_cast<int>(m_favdirs.GetCount()))
910     {
911         m_Loc->Delete(event.GetInt());
912         m_Loc->Insert(m_root,m_favdirs.GetCount());
913         m_Loc->SetSelection(m_favdirs.GetCount());
914     }
915     else
916     {
917         for(size_t i=m_favdirs.GetCount();i<m_Loc->GetCount();i++)
918         {
919             wxString cmp;
920             cmp=m_Loc->GetString(i);
921             if(cmp==m_root)
922             {
923                 m_Loc->Delete(i);
924                 m_Loc->Insert(m_root,m_favdirs.GetCount());
925                 m_Loc->SetSelection(event.GetInt());
926                 return;
927             }
928         }
929         m_Loc->Insert(m_root,m_favdirs.GetCount());
930         if(m_Loc->GetCount()>10+m_favdirs.GetCount())
931             m_Loc->Delete(10+m_favdirs.GetCount());
932         m_Loc->SetSelection(event.GetInt());
933     }
934 }
935 
OnSetLoc(wxCommandEvent &)936 void FileExplorer::OnSetLoc(wxCommandEvent &/*event*/)
937 {
938     wxString loc=GetFullPath(m_selectti[0]); //SINGLE: m_Tree->GetSelection()
939     if(!SetRootFolder(loc))
940         return;
941     m_Loc->Insert(m_root,m_favdirs.GetCount());
942     if(m_Loc->GetCount()>10+m_favdirs.GetCount())
943         m_Loc->Delete(10+m_favdirs.GetCount());
944 }
945 
OnVCSChangesCheck(wxCommandEvent &)946 void FileExplorer::OnVCSChangesCheck(wxCommandEvent &/*event*/)
947 {
948     Refresh(m_Tree->GetRootItem());
949 }
950 
OnVCSControl(wxCommandEvent &)951 void FileExplorer::OnVCSControl(wxCommandEvent &/*event*/)
952 {
953     wxString commit = m_VCS_Control->GetString(m_VCS_Control->GetSelection());
954     if (commit == _T("Select commit..."))
955     {
956         CommitBrowser *cm = new CommitBrowser(this, GetFullPath(m_Tree->GetRootItem()), m_VCS_Type->GetLabel());
957         if(cm->ShowModal() == wxID_OK)
958         {
959             commit = cm->GetSelectedCommit();
960             cm->Destroy();
961             if (commit != wxEmptyString)
962             {
963                 unsigned int i=0;
964                 for (; i<m_VCS_Control->GetCount(); ++i)
965                 {
966                     if (m_VCS_Control->GetString(i) == commit)
967                     {
968                         m_VCS_Control->SetSelection(i);
969                         break;
970                     }
971                 }
972                 if (i == m_VCS_Control->GetCount())
973                     m_VCS_Control->Append(commit);
974                 m_VCS_Control->SetSelection(m_VCS_Control->GetCount()-1);
975             }
976         }
977         else
978             commit = wxEmptyString;
979     }
980     if (commit!=wxEmptyString)
981     {
982         m_commit = commit;
983         Refresh(m_Tree->GetRootItem());
984     } else
985     {
986         unsigned int i=0;
987         for (; i<m_VCS_Control->GetCount(); ++i)
988         {
989             if (m_VCS_Control->GetString(i) == m_commit)
990             {
991                 m_VCS_Control->SetSelection(i);
992                 break;
993             }
994         }
995     }
996 }
997 
OnOpenInEditor(wxCommandEvent &)998 void FileExplorer::OnOpenInEditor(wxCommandEvent &/*event*/)
999 {
1000     for(int i=0;i<m_ticount;i++)
1001     {
1002         if (IsBrowsingVCSTree())
1003         {
1004             wxFileName path(GetFullPath(m_selectti[i]));
1005             wxString original_path = path.GetFullPath();
1006             path.MakeRelativeTo(GetRootFolder());
1007             wxString name = path.GetFullName();
1008             wxString vcs_type = m_VCS_Type->GetLabel();
1009             name = vcs_type + _T("-") + m_commit.Mid(0,6) + _T("-") + name;
1010             path.SetFullName(name);
1011             wxFileName tmp = wxFileName(wxFileName::GetTempDir(),_T(""));
1012             tmp.AppendDir(_T("codeblocks-fm"));
1013             path.MakeAbsolute(tmp.GetFullPath());
1014             if(!path.FileExists())
1015                 m_vcs_file_loader_queue.Add(_T("cat"), original_path, path.GetFullPath());
1016             else
1017                 DoOpenInEditor(path.GetFullPath());
1018         }
1019         else
1020         {
1021             wxFileName path(GetFullPath(m_selectti[i]));
1022             wxString filename=path.GetFullPath();
1023             if(!path.FileExists())
1024                 continue;
1025             DoOpenInEditor(filename);
1026         }
1027     }
1028     if (m_vcs_file_loader==0 && !m_vcs_file_loader_queue.empty())
1029     {
1030         LoaderQueueItem item = m_vcs_file_loader_queue.Pop();
1031         m_vcs_file_loader = new VCSFileLoader(this);
1032         m_vcs_file_loader->Update(item.op, item.source, item.destination, item.comp_commit);
1033     }
1034 }
1035 
OnVCSDiff(wxCommandEvent & event)1036 void FileExplorer::OnVCSDiff(wxCommandEvent &event)
1037 {
1038     wxString comp_commit;
1039     if (event.GetId() == ID_FILEDIFF) //Diff with head (for working copy) or previous (for commit)
1040         comp_commit = _T("Previous");
1041     else //Otherwise diff against specific revision
1042         comp_commit = m_VCS_Control->GetString(event.GetId()-ID_FILEDIFF1);
1043     if (m_commit == _T("Working copy") && comp_commit == _T("Working copy"))
1044         comp_commit = _T("Previous");
1045     if (comp_commit == _T("Select commit..."))
1046     {
1047         wxString diff_paths;
1048         for(int i=0;i<m_ticount;i++)
1049         {
1050             wxFileName path(GetFullPath(m_selectti[i]));
1051             path.MakeRelativeTo(GetRootFolder());
1052             if (path != wxEmptyString)
1053                 diff_paths+=_T(" \"") + path.GetFullPath() + _T("\"");
1054         }
1055         CommitBrowser *cm = new CommitBrowser(this, GetFullPath(m_Tree->GetRootItem()), m_VCS_Type->GetLabel(), diff_paths);
1056         if(cm->ShowModal() == wxID_OK)
1057         {
1058             comp_commit = cm->GetSelectedCommit();
1059         }
1060         else
1061             return;
1062     }
1063     wxString diff_paths = wxEmptyString;
1064     for(int i=0;i<m_ticount;i++)
1065     {
1066         wxFileName path(GetFullPath(m_selectti[i]));
1067         path.MakeRelativeTo(GetRootFolder());
1068         if (path != wxEmptyString)
1069             diff_paths+=_T(" \"") + path.GetFullPath() + _T("\"");
1070     }
1071     wxFileName tmp = wxFileName(wxFileName::GetTempDir(),_T(""));
1072     wxFileName root_path(GetRootFolder());
1073     wxString name = root_path.GetName();
1074     wxString vcs_type = m_VCS_Type->GetLabel();
1075     tmp.AppendDir(_T("codeblocks-fm"));
1076     name = _T("diff-") + vcs_type + _T("-") + m_commit.Mid(0,7) +_T("~") + comp_commit + _T("-") + name + _T(".patch");
1077     wxString dest_tmp_path = wxFileName(tmp.GetFullPath(), name).GetFullPath();
1078     m_vcs_file_loader_queue.Add(_T("diff"), diff_paths, dest_tmp_path, comp_commit);
1079     if (m_vcs_file_loader==0 && !m_vcs_file_loader_queue.empty())
1080     {
1081         LoaderQueueItem item = m_vcs_file_loader_queue.Pop();
1082         m_vcs_file_loader = new VCSFileLoader(this);
1083         m_vcs_file_loader->Update(item.op, item.source, item.destination, item.comp_commit);
1084     }
1085 }
1086 
OnVCSFileLoaderComplete(wxCommandEvent &)1087 void FileExplorer::OnVCSFileLoaderComplete(wxCommandEvent& /*event*/)
1088 {
1089     m_vcs_file_loader->Wait();
1090     DoOpenInEditor(m_vcs_file_loader->m_destination_path);
1091     delete m_vcs_file_loader;
1092     m_vcs_file_loader = 0;
1093     if (!m_vcs_file_loader_queue.empty())
1094     {
1095         LoaderQueueItem item = m_vcs_file_loader_queue.Pop();
1096         m_vcs_file_loader = new VCSFileLoader(this);
1097         m_vcs_file_loader->Update(item.op, item.source, item.destination, item.comp_commit);
1098     }
1099 }
1100 
DoOpenInEditor(const wxString & filename)1101 void FileExplorer::DoOpenInEditor(const wxString &filename)
1102 {
1103     EditorManager* em = Manager::Get()->GetEditorManager();
1104     EditorBase* eb = em->IsOpen(filename);
1105     if (eb)
1106     {
1107         // open files just get activated
1108         eb->Activate();
1109         return;
1110     } else
1111         em->Open(filename);
1112 }
1113 
OnActivate(wxTreeEvent & event)1114 void FileExplorer::OnActivate(wxTreeEvent &event)
1115 {
1116     if (IsBrowsingVCSTree())
1117     {
1118         //TODO: Should just retrieve the file and use the same mimetype handling as a regular file
1119         wxCommandEvent e;
1120         m_ticount=m_Tree->GetSelections(m_selectti);
1121         OnOpenInEditor(e);
1122         return;
1123     }
1124     wxString filename=GetFullPath(event.GetItem());
1125     if(m_Tree->GetItemImage(event.GetItem())==fvsFolder)
1126     {
1127         event.Skip(true);
1128         return;
1129     }
1130     EditorManager* em = Manager::Get()->GetEditorManager();
1131     EditorBase* eb = em->IsOpen(filename);
1132     if (eb)
1133     {
1134         // open files just get activated
1135         eb->Activate();
1136         return;
1137     }
1138 
1139     // Use Mime handler to open file
1140     cbMimePlugin* plugin = Manager::Get()->GetPluginManager()->GetMIMEHandlerForFile(filename);
1141     if (!plugin)
1142     {
1143         wxString msg;
1144         msg.Printf(_("Could not open file '%s'.\nNo handler registered for this type of file."), filename.c_str());
1145         LogErrorMessage(msg);
1146 //        em->Open(filename); //should never need to open the file from here
1147     }
1148     else if (plugin->OpenFile(filename) != 0)
1149     {
1150         const PluginInfo* info = Manager::Get()->GetPluginManager()->GetPluginInfo(plugin);
1151         wxString msg;
1152         msg.Printf(_("Could not open file '%s'.\nThe registered handler (%s) could not open it."), filename.c_str(), info ? info->title.c_str() : wxString(_("<Unknown plugin>")).c_str());
1153         LogErrorMessage(msg);
1154     }
1155 
1156 //    if(!em->IsOpen(file))
1157 //        em->Open(file);
1158 
1159 }
1160 
1161 
OnKeyDown(wxKeyEvent & event)1162 void FileExplorer::OnKeyDown(wxKeyEvent &event)
1163 {
1164     if(event.GetKeyCode() == WXK_DELETE)
1165     {
1166         if (IsBrowsingVCSTree())
1167         {
1168             wxCommandEvent event2;
1169             OnDelete(event2);
1170         }
1171     }
1172 }
1173 
1174 
IsBrowsingVCSTree()1175 bool FileExplorer::IsBrowsingVCSTree()
1176 {
1177     return m_commit != _T("Working copy") && m_commit != wxEmptyString;
1178 }
1179 
IsBrowsingWorkingCopy()1180 bool FileExplorer::IsBrowsingWorkingCopy()
1181 {
1182     return m_commit == _T("Working copy") && m_commit != wxEmptyString;
1183 }
1184 
OnRightClick(wxTreeEvent & event)1185 void FileExplorer::OnRightClick(wxTreeEvent &event)
1186 {
1187     wxMenu* Popup = new wxMenu();
1188     m_ticount=m_Tree->GetSelections(m_selectti);
1189     if(!IsInSelection(event.GetItem())) //replace the selection with right clicked item if right clicked item isn't in the selection
1190     {
1191         for(int i=0;i<m_ticount;i++)
1192             m_Tree->SelectItem(m_selectti[i],false);
1193         m_Tree->SelectItem(event.GetItem());
1194         m_ticount=m_Tree->GetSelections(m_selectti);
1195         m_Tree->Update();
1196     }
1197     FileTreeData* ftd = new FileTreeData(0, FileTreeData::ftdkUndefined);
1198     ftd->SetKind(FileTreeData::ftdkFile);
1199     if(m_ticount>0)
1200     {
1201         if(m_ticount==1)
1202         {
1203             int img = m_Tree->GetItemImage(m_selectti[0]);
1204             if(img==fvsFolder)
1205             {
1206                 ftd->SetKind(FileTreeData::ftdkFolder);
1207                 Popup->Append(ID_SETLOC,_("Make roo&t"));
1208                 Popup->Append(ID_FILEEXPANDALL,_("Expand all children")); //TODO: check availability in wx2.8 for win32 (not avail wx2.6)
1209                 Popup->Append(ID_FILECOLLAPSEALL,_("Collapse all children")); //TODO: check availability in wx2.8 for win32 (not avail wx2.6)
1210                 if (!IsBrowsingVCSTree())
1211                 {
1212                     Popup->Append(ID_FILEMAKEFAV,_("Add to favorites"));
1213                     Popup->Append(ID_FILENEWFILE,_("New file..."));
1214                     Popup->Append(ID_FILENEWFOLDER,_("New directory..."));
1215                     Popup->Append(ID_FILERENAME,_("&Rename..."));
1216                 }
1217             } else
1218             {
1219                 if (!IsBrowsingVCSTree())
1220                     Popup->Append(ID_FILERENAME,_("&Rename..."));
1221             }
1222         }
1223         if(IsFilesOnly(m_selectti))
1224         {
1225             Popup->Append(ID_OPENINED,_("&Open in CB editor"));
1226             if (!IsBrowsingVCSTree())
1227                 if(Manager::Get()->GetProjectManager()->GetActiveProject())
1228                     Popup->Append(ID_FILEADDTOPROJECT,_("&Add to active project..."));
1229         }
1230         if (!IsBrowsingVCSTree())
1231         {
1232             Popup->Append(ID_FILEDUP,_("&Duplicate"));
1233             Popup->Append(ID_FILECOPY,_("&Copy to..."));
1234             Popup->Append(ID_FILEMOVE,_("&Move to..."));
1235             Popup->Append(ID_FILEDELETE,_("D&elete"));
1236         }
1237         if ( IsBrowsingVCSTree() || IsBrowsingWorkingCopy() )
1238         {
1239             if (IsBrowsingWorkingCopy())
1240                 Popup->Append(ID_FILEDIFF,_("&Diff"));
1241             else
1242                 Popup->Append(ID_FILEDIFF,_("&Diff previous"));
1243             wxMenu *diff_menu = new wxMenu();
1244             unsigned int n = m_VCS_Control->GetCount();
1245             if (n>10)
1246                 n=10;
1247             if (IsBrowsingWorkingCopy())
1248             {
1249                 diff_menu->Append(ID_FILEDIFF1, _("Head"));
1250                 for (unsigned int i = 1; i<n; ++i)
1251                     diff_menu->Append(ID_FILEDIFF1 + i, m_VCS_Control->GetString(i));
1252             }
1253             else
1254             {
1255                 for (unsigned int i = 0; i<n; ++i)
1256                     diff_menu->Append(ID_FILEDIFF1 + i, m_VCS_Control->GetString(i));
1257             }
1258             Popup->AppendSubMenu(diff_menu,_("Diff against"));
1259         }
1260     }
1261     wxMenu *viewpop=new wxMenu();
1262     viewpop->Append(ID_FILESETTINGS,_("Favorite directories..."));
1263     viewpop->AppendCheckItem(ID_FILESHOWHIDDEN,_("Show &hidden files"))->Check(m_show_hidden);
1264 //    viewpop->AppendCheckItem(ID_FILEPARSECVS,_("CVS decorators"))->Check(m_parse_cvs);
1265     viewpop->AppendCheckItem(ID_FILEPARSESVN,_("SVN integration"))->Check(m_parse_svn);
1266     viewpop->AppendCheckItem(ID_FILEPARSEHG,_("Hg integration"))->Check(m_parse_hg);
1267     viewpop->AppendCheckItem(ID_FILEPARSEBZR,_("Bzr integration"))->Check(m_parse_bzr);
1268     viewpop->AppendCheckItem(ID_FILEPARSEGIT,_("Git integration"))->Check(m_parse_git);
1269     if(m_ticount>1)
1270     {
1271         ftd->SetKind(FileTreeData::ftdkVirtualGroup);
1272         wxString pathlist = GetFullPath(m_selectti[0]);
1273         for(int i=1;i<m_ticount;i++)
1274             pathlist += _T("*") + GetFullPath(m_selectti[i]); //passing a '*' separated list of files/directories to any plugin takers
1275         ftd->SetFolder(pathlist);
1276     }
1277     else if ( m_ticount > 0)
1278     {
1279         wxString filepath = GetFullPath(m_selectti[0]);
1280         ftd->SetFolder(filepath);
1281     }
1282     if(m_ticount>0)
1283         Manager::Get()->GetPluginManager()->AskPluginsForModuleMenu(mtUnknown, Popup, ftd);
1284     delete ftd;
1285     Popup->AppendSeparator();
1286     Popup->AppendSubMenu(viewpop,_("&Settings"));
1287     Popup->Append(ID_FILEREFRESH,_("Re&fresh"));
1288     wxWindow::PopupMenu(Popup);
1289     delete Popup;
1290 }
1291 
OnNewFile(wxCommandEvent &)1292 void FileExplorer::OnNewFile(wxCommandEvent &/*event*/)
1293 {
1294     wxString workingdir=GetFullPath(m_selectti[0]); //SINGLE: m_Tree->GetSelection()
1295     wxTextEntryDialog te(this,_("Name Your New File: "));
1296     if(te.ShowModal()!=wxID_OK)
1297         return;
1298     wxString name=te.GetValue();
1299     wxFileName file(workingdir);
1300     file.Assign(file.GetFullPath(),name);
1301     wxString newfile=file.GetFullPath();
1302     if(!wxFileName::FileExists(newfile) &&!wxFileName::DirExists(newfile))
1303     {
1304         wxFile fileobj;
1305         if(fileobj.Create(newfile))
1306         {
1307             fileobj.Close();
1308             Refresh(m_selectti[0]); //SINGLE: m_Tree->GetSelection()
1309         }
1310         else
1311             cbMessageBox(_("File Creation Failed"),_("Error"));
1312     }
1313     else
1314         cbMessageBox(_("File/Directory Already Exists with Name ")+name, _("Error"));
1315 }
1316 
OnAddFavorite(wxCommandEvent &)1317 void FileExplorer::OnAddFavorite(wxCommandEvent &/*event*/)
1318 {
1319     FavoriteDir fav;
1320     fav.path=GetFullPath(m_selectti[0]);
1321     if(fav.path[fav.path.Len()-1]!=wxFileName::GetPathSeparator())
1322         fav.path=fav.path+wxFileName::GetPathSeparator();
1323     wxTextEntryDialog ted(NULL,_("Enter an alias for this directory:"),_("Add Favorite Directory"),fav.path);
1324     if(ted.ShowModal()!=wxID_OK)
1325         return;
1326     wxString name=ted.GetValue();
1327     fav.alias=name;
1328     m_favdirs.Insert(fav,0);
1329     m_Loc->Insert(name,0);
1330 }
1331 
OnNewFolder(wxCommandEvent &)1332 void FileExplorer::OnNewFolder(wxCommandEvent &/*event*/)
1333 {
1334     wxString workingdir=GetFullPath(m_selectti[0]); //SINGLE: m_Tree->GetSelection()
1335     wxTextEntryDialog te(this,_("New Directory Name: "));
1336     if(te.ShowModal()!=wxID_OK)
1337         return;
1338     wxString name=te.GetValue();
1339     wxFileName dir(workingdir);
1340     dir.Assign(dir.GetFullPath(),name);
1341     wxString mkd=dir.GetFullPath();
1342     if(!wxFileName::DirExists(mkd) &&!wxFileName::FileExists(mkd))
1343     {
1344         if (!dir.Mkdir(mkd))
1345             cbMessageBox(_("A directory could not be created with name ")+name);
1346         Refresh(m_selectti[0]); //SINGLE: m_Tree->GetSelection()
1347     }
1348     else
1349         cbMessageBox(_("A file or directory already exists with name ")+name);
1350 }
1351 
OnDuplicate(wxCommandEvent &)1352 void FileExplorer::OnDuplicate(wxCommandEvent &/*event*/)
1353 {
1354     m_ticount=m_Tree->GetSelections(m_selectti);
1355     for(int i=0;i<m_ticount;i++)
1356     {
1357         wxFileName path(GetFullPath(m_selectti[i]));  //SINGLE: m_Tree->GetSelection()
1358         if(wxFileName::FileExists(path.GetFullPath())||wxFileName::DirExists(path.GetFullPath()))
1359         {
1360             if(!PromptSaveOpenFile(_("File is modified, press Yes to save before duplication, No to copy unsaved file or Cancel to skip file"),wxFileName(path)))
1361                 continue;
1362             int j=1;
1363             wxString destpath(path.GetPathWithSep()+path.GetName()+wxString::Format(_T("(%i)"),j));
1364             if(path.GetExt()!=wxEmptyString)
1365                 destpath+=_T(".")+path.GetExt();
1366             while(j<100 && (wxFileName::FileExists(destpath) || wxFileName::DirExists(destpath)))
1367             {
1368                 j++;
1369                 destpath=path.GetPathWithSep()+path.GetName()+wxString::Format(_T("(%i)"),j);
1370                 if(path.GetExt()!=wxEmptyString)
1371                     destpath+=_T(".")+path.GetExt();
1372             }
1373             if(j==100)
1374             {
1375                 cbMessageBox(_("Too many copies of file or directory"));
1376                 continue;
1377             }
1378 
1379 #ifdef __WXMSW__
1380             wxArrayString output;
1381             wxString cmdline;
1382             if(wxFileName::FileExists(path.GetFullPath()))
1383                 cmdline=_T("cmd /c copy /Y \"")+path.GetFullPath()+_T("\" \"")+destpath+_T("\"");
1384             else
1385                 cmdline=_T("cmd /c xcopy /S/E/Y/H/I \"")+path.GetFullPath()+_T("\" \"")+destpath+_T("\"");
1386             int hresult=::wxExecute(cmdline,output,wxEXEC_SYNC);
1387 #else
1388             wxString cmdline=_T("/bin/cp -r -b \"")+path.GetFullPath()+_T("\" \"")+destpath+_T("\"");
1389             int hresult=::wxExecute(cmdline,wxEXEC_SYNC);
1390 #endif
1391             if(hresult)
1392                 MessageBox(m_Tree,_("Command '")+cmdline+_("' failed with error ")+wxString::Format(_T("%i"),hresult));
1393         }
1394     }
1395     Refresh(m_Tree->GetRootItem()); //TODO: Can probably be more efficient than this
1396     //TODO: Reselect item in new location?? (what it outside root scope?)
1397 }
1398 
1399 
CopyFiles(const wxString & destination,const wxArrayString & selectedfiles)1400 void FileExplorer::CopyFiles(const wxString &destination, const wxArrayString &selectedfiles)
1401 {
1402     for(unsigned int i=0;i<selectedfiles.Count();i++)
1403     {
1404         wxString path=selectedfiles[i];
1405         wxFileName destpath;
1406         destpath.Assign(destination,wxFileName(path).GetFullName());
1407         if(destpath.SameAs(path))
1408             continue;
1409         if(wxFileName::FileExists(path)||wxFileName::DirExists(path))
1410         {
1411             if(!PromptSaveOpenFile(_("File is modified, press Yes to save before duplication, No to copy unsaved file or Cancel to skip file"),wxFileName(path)))
1412                 continue;
1413 #ifdef __WXMSW__
1414             wxArrayString output;
1415             wxString cmdline;
1416             if(wxFileName::FileExists(path))
1417                 cmdline=_T("cmd /c copy /Y \"")+path+_T("\" \"")+destpath.GetFullPath()+_T("\"");
1418             else
1419                 cmdline=_T("cmd /c xcopy /S/E/Y/H/I \"")+path+_T("\" \"")+destpath.GetFullPath()+_T("\"");
1420             int hresult=::wxExecute(cmdline,output,wxEXEC_SYNC);
1421 #else
1422             int hresult=::wxExecute(_T("/bin/cp -r -b \"")+path+_T("\" \"")+destpath.GetFullPath()+_T("\""),wxEXEC_SYNC);
1423 #endif
1424             if(hresult)
1425                 MessageBox(m_Tree,_("Copying '")+path+_("' failed with error ")+wxString::Format(_T("%i"),hresult));
1426         }
1427     }
1428 }
1429 
OnCopy(wxCommandEvent &)1430 void FileExplorer::OnCopy(wxCommandEvent &/*event*/)
1431 {
1432     wxDirDialog dd(this,_("Copy to"));
1433     dd.SetPath(GetFullPath(m_Tree->GetRootItem()));
1434     wxArrayString selectedfiles;
1435     m_ticount=m_Tree->GetSelections(m_selectti);
1436     for(int i=0;i<m_ticount;i++) // really important not to rely on TreeItemId ater modal dialogs because file updates can change the file tree in the background.
1437     {
1438         selectedfiles.Add(GetFullPath(m_selectti[i]));  //SINGLE: m_Tree->GetSelection()
1439     }
1440     if(dd.ShowModal()==wxID_CANCEL)
1441         return;
1442     CopyFiles(dd.GetPath(),selectedfiles);
1443 //    Refresh(m_Tree->GetRootItem()); //TODO: Use this if monitoring not available
1444     //TODO: Reselect item in new location?? (what if outside root scope?)
1445 }
1446 
MoveFiles(const wxString & destination,const wxArrayString & selectedfiles)1447 void FileExplorer::MoveFiles(const wxString &destination, const wxArrayString &selectedfiles)
1448 {
1449     for(unsigned int i=0;i<selectedfiles.Count();i++)
1450     {
1451         wxString path=selectedfiles[i];
1452         wxFileName destpath;
1453         destpath.Assign(destination,wxFileName(path).GetFullName());
1454         if(destpath.SameAs(path)) //TODO: Log message that can't copy over self.
1455             continue;
1456         if(wxFileName::FileExists(path)||wxFileName::DirExists(path))
1457         {
1458 #ifdef __WXMSW__
1459             wxArrayString output;
1460             int hresult=::wxExecute(_T("cmd /c move /Y \"")+path+_T("\" \"")+destpath.GetFullPath()+_T("\""),output,wxEXEC_SYNC);
1461 #else
1462             int hresult=::wxExecute(_T("/bin/mv -b \"")+path+_T("\" \"")+destpath.GetFullPath()+_T("\""),wxEXEC_SYNC);
1463 #endif
1464             if(hresult)
1465                 MessageBox(m_Tree,_("Moving '")+path+_("' failed with error ")+wxString::Format(_T("%i"),hresult));
1466         }
1467     }
1468 }
1469 
OnMove(wxCommandEvent &)1470 void FileExplorer::OnMove(wxCommandEvent &/*event*/)
1471 {
1472     wxDirDialog dd(this,_("Move to"));
1473     wxArrayString selectedfiles;
1474     m_ticount=m_Tree->GetSelections(m_selectti);
1475     for(int i=0;i<m_ticount;i++)
1476         selectedfiles.Add(GetFullPath(m_selectti[i]));  //SINGLE: m_Tree->GetSelection()
1477     dd.SetPath(GetFullPath(m_Tree->GetRootItem()));
1478     if(dd.ShowModal()==wxID_CANCEL)
1479         return;
1480     MoveFiles(dd.GetPath(),selectedfiles);
1481 //    Refresh(m_Tree->GetRootItem()); //TODO: Can probably be more efficient than this
1482     //TODO: Reselect item in new location?? (what if outside root scope?)
1483 }
1484 
GetSelectedPaths()1485 wxArrayString FileExplorer::GetSelectedPaths()
1486 {
1487     wxArrayString paths;
1488     for(int i=0;i<m_ticount;i++)
1489     {
1490         wxString path(GetFullPath(m_selectti[i]));  //SINGLE: m_Tree->GetSelection()
1491         paths.Add(path);
1492     }
1493     return paths;
1494 }
1495 
OnDelete(wxCommandEvent &)1496 void FileExplorer::OnDelete(wxCommandEvent &/*event*/)
1497 {
1498     m_ticount=m_Tree->GetSelections(m_selectti);
1499     wxArrayString as=GetSelectedPaths();
1500     wxString prompt=_("Your are about to delete\n\n");
1501     for(unsigned int i=0;i<as.Count();i++)
1502         prompt+=as[i]+_("\n");
1503     prompt+=_("\nAre you sure?");
1504     if(MessageBox(m_Tree,prompt,_("Delete"),wxYES_NO)!=wxID_YES)
1505         return;
1506     for(unsigned int i=0;i<as.Count();i++)
1507     {
1508         wxString path=as[i];  //SINGLE: m_Tree->GetSelection()
1509         if(wxFileName::FileExists(path))
1510         {
1511             //        EditorManager* em = Manager::Get()->GetEditorManager();
1512             //        if(em->IsOpen(path))
1513             //        {
1514             //            cbMessageBox(_("Close file ")+path.GetFullPath()+_(" first"));
1515             //            return;
1516             //        }
1517             if(!::wxRemoveFile(path))
1518                 MessageBox(m_Tree,_("Delete file '")+path+_("' failed"));
1519         } else
1520         if(wxFileName::DirExists(path))
1521         {
1522 #ifdef __WXMSW__
1523             wxArrayString output;
1524             int hresult=::wxExecute(_T("cmd /c rmdir /S/Q \"")+path+_T("\""),output,wxEXEC_SYNC);
1525 #else
1526             int hresult=::wxExecute(_T("/bin/rm -r -f \"")+path+_T("\""),wxEXEC_SYNC);
1527 #endif
1528             if(hresult)
1529                 MessageBox(m_Tree,_("Delete directory '")+path+_("' failed with error ")+wxString::Format(_T("%i"),hresult));
1530         }
1531     }
1532     Refresh(m_Tree->GetRootItem());
1533 }
1534 
OnRename(wxCommandEvent &)1535 void FileExplorer::OnRename(wxCommandEvent &/*event*/)
1536 {
1537     wxString path(GetFullPath(m_selectti[0]));  //SINGLE: m_Tree->GetSelection()
1538     if(wxFileName::FileExists(path))
1539     {
1540         EditorManager* em = Manager::Get()->GetEditorManager();
1541         if(em->IsOpen(path))
1542         {
1543             cbMessageBox(_("Close file first"));
1544             return;
1545         }
1546         wxTextEntryDialog te(this,_("New name:"),_("Rename File"),wxFileName(path).GetFullName());
1547         if(te.ShowModal()==wxID_CANCEL)
1548             return;
1549         wxFileName destpath(path);
1550         destpath.SetFullName(te.GetValue());
1551         if(!::wxRenameFile(path,destpath.GetFullPath()))
1552             cbMessageBox(_("Rename failed"));
1553     }
1554     if(wxFileName::DirExists(path))
1555     {
1556         wxTextEntryDialog te(this,_("New name:"),_("Rename File"),wxFileName(path).GetFullName());
1557         if(te.ShowModal()==wxID_CANCEL)
1558             return;
1559         wxFileName destpath(path);
1560         destpath.SetFullName(te.GetValue());
1561 #ifdef __WXMSW__
1562         wxArrayString output;
1563         int hresult=::wxExecute(_T("cmd /c move /Y \"")+path+_T("\" \"")+destpath.GetFullPath()+_T("\""),output,wxEXEC_SYNC);
1564 #else
1565         int hresult=::wxExecute(_T("/bin/mv \"")+path+_T("\" \"")+destpath.GetFullPath()+_T("\""),wxEXEC_SYNC);
1566 #endif
1567         if(hresult)
1568             MessageBox(m_Tree,_("Rename directory '")+path+_("' failed with error ")+wxString::Format(_T("%i"),hresult));
1569     }
1570     Refresh(m_Tree->GetItemParent(m_selectti[0])); //SINGLE: m_Tree->GetSelection()
1571 }
1572 
OnExpandAll(wxCommandEvent &)1573 void FileExplorer::OnExpandAll(wxCommandEvent &/*event*/)
1574 {
1575     m_Tree->ExpandAllChildren(m_Tree->GetSelection());
1576 }
1577 
OnCollapseAll(wxCommandEvent &)1578 void FileExplorer::OnCollapseAll(wxCommandEvent &/*event*/)
1579 {
1580     m_Tree->CollapseAllChildren(m_Tree->GetSelection());
1581 }
1582 
OnSettings(wxCommandEvent &)1583 void FileExplorer::OnSettings(wxCommandEvent &/*event*/)
1584 {
1585     FileBrowserSettings fbs(m_favdirs,NULL);
1586     if(fbs.ShowModal()==wxID_OK)
1587     {
1588         size_t count=m_favdirs.GetCount();
1589         for(size_t i=0;i<count;i++)
1590             m_Loc->Delete(0);
1591         m_favdirs=fbs.m_favdirs;
1592         count=m_favdirs.GetCount();
1593         for(size_t i=0;i<count;i++)
1594             m_Loc->Insert(m_favdirs[i].alias,i);
1595     }
1596 
1597 }
1598 
OnShowHidden(wxCommandEvent &)1599 void FileExplorer::OnShowHidden(wxCommandEvent &/*event*/)
1600 {
1601     m_show_hidden=!m_show_hidden;
1602     Refresh(m_Tree->GetRootItem());
1603 }
1604 
OnParseCVS(wxCommandEvent &)1605 void FileExplorer::OnParseCVS(wxCommandEvent &/*event*/)
1606 {
1607     m_parse_cvs=!m_parse_cvs;
1608     //cfg->Clear();
1609     Refresh(m_Tree->GetRootItem());
1610 }
1611 
OnParseSVN(wxCommandEvent &)1612 void FileExplorer::OnParseSVN(wxCommandEvent &/*event*/)
1613 {
1614     m_parse_svn=!m_parse_svn;
1615     Refresh(m_Tree->GetRootItem());
1616 }
1617 
OnParseGIT(wxCommandEvent &)1618 void FileExplorer::OnParseGIT(wxCommandEvent &/*event*/)
1619 {
1620     m_parse_git=!m_parse_git;
1621     Refresh(m_Tree->GetRootItem());
1622 }
1623 
OnParseHG(wxCommandEvent &)1624 void FileExplorer::OnParseHG(wxCommandEvent &/*event*/)
1625 {
1626     m_parse_hg=!m_parse_hg;
1627     Refresh(m_Tree->GetRootItem());
1628 }
1629 
OnParseBZR(wxCommandEvent &)1630 void FileExplorer::OnParseBZR(wxCommandEvent &/*event*/)
1631 {
1632     m_parse_bzr=!m_parse_bzr;
1633     Refresh(m_Tree->GetRootItem());
1634 }
1635 
OnUpButton(wxCommandEvent &)1636 void FileExplorer::OnUpButton(wxCommandEvent &/*event*/)
1637 {
1638     wxFileName loc(m_root);
1639     if (loc.GetDirCount())
1640     {
1641         loc.RemoveLastDir();
1642         SetRootFolder(loc.GetFullPath());
1643     }
1644 }
1645 
OnRefresh(wxCommandEvent &)1646 void FileExplorer::OnRefresh(wxCommandEvent &/*event*/)
1647 {
1648     if(m_Tree->GetItemImage(m_selectti[0])==fvsFolder) //SINGLE: m_Tree->GetSelection()
1649         Refresh(m_selectti[0]); //SINGLE: m_Tree->GetSelection()
1650     else
1651         Refresh(m_Tree->GetRootItem());
1652 }
1653 
1654 //TODO: Set copy cursor state if necessary
OnBeginDragTreeItem(wxTreeEvent & event)1655 void FileExplorer::OnBeginDragTreeItem(wxTreeEvent &event)
1656 {
1657 //    SetCursor(wxCROSS_CURSOR);
1658 //    if(IsInSelection(event.GetItem()))
1659 //        return; // don't start a drag for an unselected item
1660     if (!IsBrowsingVCSTree())
1661         event.Allow();
1662 //    m_dragtest=GetFullPath(event.GetItem());
1663     m_ticount=m_Tree->GetSelections(m_selectti);
1664 }
1665 
IsInSelection(const wxTreeItemId & ti)1666 bool FileExplorer::IsInSelection(const wxTreeItemId &ti)
1667 {
1668     for(int i=0;i<m_ticount;i++)
1669         if(ti==m_selectti[i])
1670             return true;
1671     return false;
1672 }
1673 
1674 //TODO: End copy cursor state if necessary
OnEndDragTreeItem(wxTreeEvent & event)1675 void FileExplorer::OnEndDragTreeItem(wxTreeEvent &event)
1676 {
1677 //    SetCursor(wxCursor(wxCROSS_CURSOR));
1678     if(m_Tree->GetItemImage(event.GetItem())!=fvsFolder) //can only copy to folders
1679         return;
1680     for(int i=0;i<m_ticount;i++)
1681     {
1682         wxString path(GetFullPath(m_selectti[i]));
1683         wxFileName destpath;
1684         if(!event.GetItem().IsOk())
1685             return;
1686         destpath.Assign(GetFullPath(event.GetItem()),wxFileName(path).GetFullName());
1687         if(destpath.SameAs(path))
1688             continue;
1689         if(wxFileName::DirExists(path)||wxFileName::FileExists(path))
1690         {
1691             if(!::wxGetKeyState(WXK_CONTROL))
1692             {
1693                 if(wxFileName::FileExists(path))
1694                     if(!PromptSaveOpenFile(_("File is modified, press Yes to save before move, No to move unsaved file or Cancel to skip file"),wxFileName(path)))
1695                         continue;
1696 #ifdef __WXMSW__
1697                 wxArrayString output;
1698                 int hresult=::wxExecute(_T("cmd /c move /Y \"")+path+_T("\" \"")+destpath.GetFullPath()+_T("\""),output,wxEXEC_SYNC);
1699 #else
1700                 int hresult=::wxExecute(_T("/bin/mv -b \"")+path+_T("\" \"")+destpath.GetFullPath()+_T("\""),wxEXEC_SYNC);
1701 #endif
1702                 if(hresult)
1703                     MessageBox(m_Tree,_("Move directory '")+path+_("' failed with error ")+wxString::Format(_T("%i"),hresult));
1704             } else
1705             {
1706                 if(wxFileName::FileExists(path))
1707                     if(!PromptSaveOpenFile(_("File is modified, press Yes to save before copy, No to copy unsaved file or Cancel to skip file"),wxFileName(path)))
1708                         continue;
1709 #ifdef __WXMSW__
1710                 wxArrayString output;
1711                 wxString cmdline;
1712                 if(wxFileName::FileExists(path))
1713                     cmdline=_T("cmd /c copy /Y \"")+path+_T("\" \"")+destpath.GetFullPath()+_T("\"");
1714                 else
1715                     cmdline=_T("cmd /c xcopy /S/E/Y/H/I \"")+path+_T("\" \"")+destpath.GetFullPath()+_T("\"");
1716                 int hresult=::wxExecute(cmdline,output,wxEXEC_SYNC);
1717 #else
1718                 int hresult=::wxExecute(_T("/bin/cp -r -b \"")+path+_T("\" \"")+destpath.GetFullPath()+_T("\""),wxEXEC_SYNC);
1719 #endif
1720                 if(hresult)
1721                     MessageBox(m_Tree,_("Copy directory '")+path+_("' failed with error ")+wxString::Format(_T("%i"),hresult));
1722             }
1723         }
1724 //        if(!PromptSaveOpenFile(_T("File is modified, press \"Yes\" to save before move/copy, \"No\" to move/copy unsaved file or \"Cancel\" to abort the operation"),path)) //TODO: specify move or copy depending on whether CTRL held down
1725 //            return;
1726     }
1727     Refresh(m_Tree->GetRootItem());
1728 }
1729 
OnAddToProject(wxCommandEvent &)1730 void FileExplorer::OnAddToProject(wxCommandEvent &/*event*/)
1731 {
1732     wxArrayString files;
1733     wxString file;
1734     for(int i=0;i<m_ticount;i++)
1735     {
1736         file=GetFullPath(m_selectti[i]);
1737         if(wxFileName::FileExists(file))
1738             files.Add(file);
1739     }
1740     wxArrayInt prompt;
1741     Manager::Get()->GetProjectManager()->AddMultipleFilesToProject(files, NULL, prompt);
1742     Manager::Get()->GetProjectManager()->GetUI().RebuildTree();
1743 }
1744 
IsFilesOnly(wxArrayTreeItemIds tis)1745 bool FileExplorer::IsFilesOnly(wxArrayTreeItemIds tis)
1746 {
1747     for(size_t i=0;i<tis.GetCount();i++)
1748         if(m_Tree->GetItemImage(tis[i])==fvsFolder)
1749             return false;
1750     return true;
1751 }
1752