1 /////////////////////////////////////////////////////////////////////////////
2 // Name: samples/fswatcher/fswatcher.cpp
3 // Purpose: wxFileSystemWatcher sample
4 // Author: Bartosz Bekier
7 // Copyright: (c) Bartosz Bekier
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 #include "wx/wxprec.h"
21 #include "../sample.xpm"
24 #include "wx/fswatcher.h"
25 #include "wx/listctrl.h"
27 // Define a new frame type: this is going to be our main frame
28 class MyFrame
: public wxFrame
31 MyFrame(const wxString
& title
);
35 // file system watcher creation
36 void OnEventLoopEnter();
40 void OnClear(wxCommandEvent
& WXUNUSED(event
)) { m_evtConsole
->Clear(); }
41 void OnQuit(wxCommandEvent
& WXUNUSED(event
)) { Close(true); }
42 void OnWatch(wxCommandEvent
& event
);
43 void OnAbout(wxCommandEvent
& event
);
45 void OnAdd(wxCommandEvent
& event
);
46 void OnRemove(wxCommandEvent
& event
);
48 void OnFileSystemEvent(wxFileSystemWatcherEvent
& event
);
49 void LogEvent(const wxFileSystemWatcherEvent
& event
);
51 wxTextCtrl
*m_evtConsole
; // events console
52 wxListView
*m_filesList
; // list of watched paths
53 wxFileSystemWatcher
* m_watcher
; // file system watcher
57 const static wxString LOG_FORMAT
; // how to format events
60 const wxString
MyFrame::LOG_FORMAT
= " %-12s %-36s %-36s";
62 // Define a new application type, each program should derive a class from wxApp
63 class MyApp
: public wxApp
66 // 'Main program' equivalent: the program execution "starts" here
69 wxLog::AddTraceMask("EventSource");
70 wxLog::AddTraceMask(wxTRACE_FSWATCHER
);
72 // create the main application window
73 m_frame
= new MyFrame("File System Watcher wxWidgets App");
75 // If we returned false here, the application would exit immediately.
79 // create the file system watcher here, because it needs an active loop
80 virtual void OnEventLoopEnter(wxEventLoopBase
* WXUNUSED(loop
))
82 m_frame
->OnEventLoopEnter();
89 // Create a new application object: this macro will allow wxWidgets to create
90 // the application object during program execution (it's better than using a
91 // static object for many reasons) and also declares the accessor function
92 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
97 // ============================================================================
99 // ============================================================================
102 MyFrame::MyFrame(const wxString
& title
)
103 : wxFrame(NULL
, wxID_ANY
, title
),
106 SetIcon(wxICON(sample
));
108 // IDs for menu and buttons
111 MENU_ID_QUIT
= wxID_EXIT
,
112 MENU_ID_CLEAR
= wxID_CLEAR
,
119 // ================================================================
123 wxMenu
*menuFile
= new wxMenu
;
124 menuFile
->Append(MENU_ID_CLEAR
, "&Clear log\tCtrl-L");
125 menuFile
->AppendSeparator();
126 menuFile
->Append(MENU_ID_QUIT
, "E&xit\tAlt-X", "Quit this program");
129 wxMenu
*menuMon
= new wxMenu
;
130 wxMenuItem
* it
= menuMon
->AppendCheckItem(MENU_ID_WATCH
, "&Watch\tCtrl-W");
131 // started by default, because file system watcher is started by default
134 // the "About" item should be in the help menu
135 wxMenu
*menuHelp
= new wxMenu
;
136 menuHelp
->Append(wxID_ABOUT
, "&About...\tF1", "Show about dialog");
138 // now append the freshly created menu to the menu bar...
139 wxMenuBar
*menuBar
= new wxMenuBar();
140 menuBar
->Append(menuFile
, "&File");
141 menuBar
->Append(menuMon
, "&Watch");
142 menuBar
->Append(menuHelp
, "&Help");
144 // ... and attach this menu bar to the frame
147 // ================================================================
151 wxPanel
*panel
= new wxPanel(this);
152 wxSizer
*panelSizer
= new wxGridSizer(2);
153 wxBoxSizer
*leftSizer
= new wxBoxSizer(wxVERTICAL
);
156 wxStaticText
* label
= new wxStaticText(panel
, wxID_ANY
, "Watched paths");
157 leftSizer
->Add(label
, wxSizerFlags().Center().Border(wxALL
));
160 m_filesList
= new wxListView(panel
, wxID_ANY
, wxPoint(-1,-1),
161 wxSize(300,200), wxLC_LIST
| wxLC_SINGLE_SEL
);
162 leftSizer
->Add(m_filesList
, wxSizerFlags(1).Expand());
165 wxButton
* buttonAdd
= new wxButton(panel
, BTN_ID_ADD
, "&Add");
166 wxButton
* buttonRemove
= new wxButton(panel
, BTN_ID_REMOVE
, "&Remove");
167 wxSizer
*btnSizer
= new wxGridSizer(2);
168 btnSizer
->Add(buttonAdd
, wxSizerFlags().Center().Border(wxALL
));
169 btnSizer
->Add(buttonRemove
, wxSizerFlags().Center().Border(wxALL
));
171 // and put it all together
172 leftSizer
->Add(btnSizer
, wxSizerFlags(0).Expand());
173 panelSizer
->Add(leftSizer
, wxSizerFlags(1).Expand());
174 panel
->SetSizerAndFit(panelSizer
);
176 // ================================================================
179 wxTextCtrl
*headerText
= new wxTextCtrl(this, wxID_ANY
, "",
180 wxDefaultPosition
, wxDefaultSize
,
182 wxString h
= wxString::Format(LOG_FORMAT
, "event", "path", "new path");
183 headerText
->SetValue(h
);
186 m_evtConsole
= new wxTextCtrl(this, wxID_ANY
, "",
187 wxDefaultPosition
, wxSize(200,200),
188 wxTE_MULTILINE
|wxTE_READONLY
|wxHSCROLL
);
190 // set monospace font to have output in nice columns
191 wxFont
font(9, wxFONTFAMILY_TELETYPE
,
192 wxFONTSTYLE_NORMAL
, wxFONTWEIGHT_NORMAL
);
193 headerText
->SetFont(font
);
194 m_evtConsole
->SetFont(font
);
196 // ================================================================
197 // laying out whole frame
199 wxBoxSizer
*sizer
= new wxBoxSizer(wxVERTICAL
);
200 sizer
->Add(panel
, wxSizerFlags(1).Expand());
201 sizer
->Add(headerText
, wxSizerFlags().Expand());
202 sizer
->Add(m_evtConsole
, wxSizerFlags(1).Expand());
203 SetSizerAndFit(sizer
);
205 // set size and position on screen
209 // ================================================================
210 // event handlers & show
213 Connect(MENU_ID_CLEAR
, wxEVT_COMMAND_MENU_SELECTED
,
214 wxCommandEventHandler(MyFrame::OnClear
));
215 Connect(MENU_ID_QUIT
, wxEVT_COMMAND_MENU_SELECTED
,
216 wxCommandEventHandler(MyFrame::OnQuit
));
217 Connect(MENU_ID_WATCH
, wxEVT_COMMAND_MENU_SELECTED
,
218 wxCommandEventHandler(MyFrame::OnWatch
));
219 Connect(wxID_ABOUT
, wxEVT_COMMAND_MENU_SELECTED
,
220 wxCommandEventHandler(MyFrame::OnAbout
));
223 Connect(BTN_ID_ADD
, wxEVT_COMMAND_BUTTON_CLICKED
,
224 wxCommandEventHandler(MyFrame::OnAdd
));
225 Connect(BTN_ID_REMOVE
, wxEVT_COMMAND_BUTTON_CLICKED
,
226 wxCommandEventHandler(MyFrame::OnRemove
));
228 // and show itself (the frames, unlike simple controls, are not shown when
229 // created initially)
238 void MyFrame::OnEventLoopEnter()
244 Connect(wxEVT_FSWATCHER
,
245 wxFileSystemWatcherEventHandler(MyFrame::OnFileSystemEvent
));
248 void MyFrame::CreateWatcher()
250 wxCHECK_RET(!m_watcher
, "Watcher already initialized");
251 m_watcher
= new wxFileSystemWatcher();
252 m_watcher
->SetOwner(this);
255 // ============================================================================
257 // ============================================================================
259 void MyFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
261 wxMessageBox("Demonstrates the usage of file system watcher, "
262 "the wxWidgets monitoring system notifying you of "
263 "changes done to your files.\n"
264 "(c) 2009 Bartosz Bekier\n",
265 "About wxWidgets File System Watcher Sample",
266 wxOK
| wxICON_INFORMATION
, this);
269 void MyFrame::OnWatch(wxCommandEvent
& event
)
271 wxLogDebug("%s start=%d", __WXFUNCTION__
, event
.IsChecked());
273 if (event
.IsChecked())
275 wxCHECK_RET(!m_watcher
, "Watcher already initialized");
280 wxCHECK_RET(m_watcher
, "Watcher not initialized");
281 m_filesList
->DeleteAllItems();
286 void MyFrame::OnAdd(wxCommandEvent
& WXUNUSED(event
))
288 wxCHECK_RET(m_watcher
, "Watcher not initialized");
290 // TODO account for adding the files as well
291 const wxString
& dir
= wxDirSelector("Choose a folder to watch", "",
292 wxDD_DEFAULT_STYLE
| wxDD_DIR_MUST_EXIST
);
296 wxLogDebug("Adding directory: '%s'", dir
);
298 if (!m_watcher
->Add(wxFileName::DirName(dir
), wxFSW_EVENT_ALL
))
300 wxLogError("Error adding '%s' to watched paths", dir
);
304 m_filesList
->InsertItem(m_filesList
->GetItemCount(), dir
);
308 void MyFrame::OnRemove(wxCommandEvent
& WXUNUSED(event
))
310 wxCHECK_RET(m_watcher
, "Watcher not initialized");
311 long idx
= m_filesList
->GetFirstSelected();
315 wxString path
= m_filesList
->GetItemText(idx
);
317 // TODO we know it is a dir, but it doesn't have to be
318 if (!m_watcher
->Remove(wxFileName::DirName(path
)))
320 wxLogError("Error removing '%s' from watched paths", path
);
324 m_filesList
->DeleteItem(idx
);
328 void MyFrame::OnFileSystemEvent(wxFileSystemWatcherEvent
& event
)
330 // TODO remove when code is rock-solid
331 wxLogDebug(wxTRACE_FSWATCHER
, "*** %s ***", event
.ToString());
336 static wxString
GetFSWEventChangeTypeName(int changeType
)
340 case wxFSW_EVENT_CREATE
:
342 case wxFSW_EVENT_DELETE
:
344 case wxFSW_EVENT_RENAME
:
346 case wxFSW_EVENT_MODIFY
:
348 case wxFSW_EVENT_ACCESS
:
352 return "INVALID_TYPE";
355 void MyFrame::LogEvent(const wxFileSystemWatcherEvent
& event
)
357 wxString entry
= wxString::Format(LOG_FORMAT
+ "\n",
358 GetFSWEventChangeTypeName(event
.GetChangeType()),
359 event
.GetPath().GetFullPath(),
360 event
.GetNewPath().GetFullPath());
361 m_evtConsole
->AppendText(entry
);