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 // TODO remove then this code becomes rock-solid
70 wxLog::AddTraceMask(wxTRACE_EVT_SOURCE
);
71 wxLog::AddTraceMask(wxTRACE_FSWATCHER
);
73 // create the main application window
74 m_frame
= new MyFrame("File System Watcher wxWidgets App");
76 // If we returned false here, the application would exit immediately.
80 // create the file system watcher here, because it needs an active loop
81 virtual void OnEventLoopEnter(wxEventLoopBase
* WXUNUSED(loop
))
83 m_frame
->OnEventLoopEnter();
90 // Create a new application object: this macro will allow wxWidgets to create
91 // the application object during program execution (it's better than using a
92 // static object for many reasons) and also declares the accessor function
93 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
98 // ============================================================================
100 // ============================================================================
103 MyFrame::MyFrame(const wxString
& title
)
104 : wxFrame(NULL
, wxID_ANY
, title
),
107 SetIcon(wxICON(sample
));
109 // IDs for menu and buttons
112 MENU_ID_QUIT
= wxID_EXIT
,
113 MENU_ID_CLEAR
= wxID_CLEAR
,
120 // ================================================================
124 wxMenu
*menuFile
= new wxMenu
;
125 menuFile
->Append(MENU_ID_CLEAR
, "&Clear log\tCtrl-L");
126 menuFile
->AppendSeparator();
127 menuFile
->Append(MENU_ID_QUIT
, "E&xit\tAlt-X", "Quit this program");
130 wxMenu
*menuMon
= new wxMenu
;
131 wxMenuItem
* it
= menuMon
->AppendCheckItem(MENU_ID_WATCH
, "&Watch\tCtrl-W");
132 // started by default, because file system watcher is started by default
135 // the "About" item should be in the help menu
136 wxMenu
*menuHelp
= new wxMenu
;
137 menuHelp
->Append(wxID_ABOUT
, "&About...\tF1", "Show about dialog");
139 // now append the freshly created menu to the menu bar...
140 wxMenuBar
*menuBar
= new wxMenuBar();
141 menuBar
->Append(menuFile
, "&File");
142 menuBar
->Append(menuMon
, "&Watch");
143 menuBar
->Append(menuHelp
, "&Help");
145 // ... and attach this menu bar to the frame
148 // ================================================================
152 wxPanel
*panel
= new wxPanel(this);
153 wxSizer
*panelSizer
= new wxGridSizer(2);
154 wxBoxSizer
*leftSizer
= new wxBoxSizer(wxVERTICAL
);
157 wxStaticText
* label
= new wxStaticText(panel
, wxID_ANY
, "Watched paths");
158 leftSizer
->Add(label
, wxSizerFlags().Center().Border(wxALL
));
161 m_filesList
= new wxListView(panel
, wxID_ANY
, wxPoint(-1,-1),
162 wxSize(300,200), wxLC_LIST
| wxLC_SINGLE_SEL
);
163 leftSizer
->Add(m_filesList
, wxSizerFlags(1).Expand());
166 wxButton
* buttonAdd
= new wxButton(panel
, BTN_ID_ADD
, "&Add");
167 wxButton
* buttonRemove
= new wxButton(panel
, BTN_ID_REMOVE
, "&Remove");
168 wxSizer
*btnSizer
= new wxGridSizer(2);
169 btnSizer
->Add(buttonAdd
, wxSizerFlags().Center().Border(wxALL
));
170 btnSizer
->Add(buttonRemove
, wxSizerFlags().Center().Border(wxALL
));
172 // and put it all together
173 leftSizer
->Add(btnSizer
, wxSizerFlags(0).Expand());
174 panelSizer
->Add(leftSizer
, wxSizerFlags(1).Expand());
175 panel
->SetSizerAndFit(panelSizer
);
177 // ================================================================
180 wxTextCtrl
*headerText
= new wxTextCtrl(this, wxID_ANY
, "",
181 wxDefaultPosition
, wxDefaultSize
,
183 wxString h
= wxString::Format(LOG_FORMAT
, "event", "path", "new path");
184 headerText
->SetValue(h
);
187 m_evtConsole
= new wxTextCtrl(this, wxID_ANY
, "",
188 wxDefaultPosition
, wxSize(200,200),
189 wxTE_MULTILINE
|wxTE_READONLY
|wxHSCROLL
);
191 // set monospace font to have output in nice columns
192 wxFont
font(9, wxFONTFAMILY_TELETYPE
,
193 wxFONTSTYLE_NORMAL
, wxFONTWEIGHT_NORMAL
);
194 headerText
->SetFont(font
);
195 m_evtConsole
->SetFont(font
);
197 // ================================================================
198 // laying out whole frame
200 wxBoxSizer
*sizer
= new wxBoxSizer(wxVERTICAL
);
201 sizer
->Add(panel
, wxSizerFlags(1).Expand());
202 sizer
->Add(headerText
, wxSizerFlags().Expand());
203 sizer
->Add(m_evtConsole
, wxSizerFlags(1).Expand());
204 SetSizerAndFit(sizer
);
206 // set size and position on screen
210 // ================================================================
211 // event handlers & show
214 Connect(MENU_ID_CLEAR
, wxEVT_COMMAND_MENU_SELECTED
,
215 wxCommandEventHandler(MyFrame::OnClear
));
216 Connect(MENU_ID_QUIT
, wxEVT_COMMAND_MENU_SELECTED
,
217 wxCommandEventHandler(MyFrame::OnQuit
));
218 Connect(MENU_ID_WATCH
, wxEVT_COMMAND_MENU_SELECTED
,
219 wxCommandEventHandler(MyFrame::OnWatch
));
220 Connect(wxID_ABOUT
, wxEVT_COMMAND_MENU_SELECTED
,
221 wxCommandEventHandler(MyFrame::OnAbout
));
224 Connect(BTN_ID_ADD
, wxEVT_COMMAND_BUTTON_CLICKED
,
225 wxCommandEventHandler(MyFrame::OnAdd
));
226 Connect(BTN_ID_REMOVE
, wxEVT_COMMAND_BUTTON_CLICKED
,
227 wxCommandEventHandler(MyFrame::OnRemove
));
229 // and show itself (the frames, unlike simple controls, are not shown when
230 // created initially)
239 void MyFrame::OnEventLoopEnter()
245 Connect(wxEVT_FSWATCHER
,
246 wxFileSystemWatcherEventHandler(MyFrame::OnFileSystemEvent
));
249 void MyFrame::CreateWatcher()
251 wxCHECK_RET(!m_watcher
, "Watcher already initialized");
252 m_watcher
= new wxFileSystemWatcher();
253 m_watcher
->SetOwner(this);
256 // ============================================================================
258 // ============================================================================
260 void MyFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
262 wxMessageBox("Demonstrates the usage of file system watcher, "
263 "the wxWidgets monitoring system notifying you of "
264 "changes done to your files.\n"
265 "(c) 2009 Bartosz Bekier\n",
266 "About wxWidgets File System Watcher Sample",
267 wxOK
| wxICON_INFORMATION
, this);
270 void MyFrame::OnWatch(wxCommandEvent
& event
)
272 wxLogDebug("%s start=%d", __WXFUNCTION__
, event
.IsChecked());
274 if (event
.IsChecked())
276 wxCHECK_RET(!m_watcher
, "Watcher already initialized");
281 wxCHECK_RET(m_watcher
, "Watcher not initialized");
282 m_filesList
->DeleteAllItems();
288 void MyFrame::OnAdd(wxCommandEvent
& WXUNUSED(event
))
290 wxCHECK_RET(m_watcher
, "Watcher not initialized");
292 // TODO account for adding the files as well
293 const wxString
& dir
= wxDirSelector("Choose a folder to watch", "",
294 wxDD_DEFAULT_STYLE
| wxDD_DIR_MUST_EXIST
);
298 wxLogDebug("Adding directory: '%s'", dir
);
300 if (!m_watcher
->Add(wxFileName::DirName(dir
), wxFSW_EVENT_ALL
))
302 wxLogError("Error adding '%s' to watched paths", dir
);
306 m_filesList
->InsertItem(m_filesList
->GetItemCount(), dir
);
310 void MyFrame::OnRemove(wxCommandEvent
& WXUNUSED(event
))
312 wxCHECK_RET(m_watcher
, "Watcher not initialized");
313 long idx
= m_filesList
->GetFirstSelected();
317 wxString path
= m_filesList
->GetItemText(idx
);
319 // TODO we know it is a dir, but it doesn't have to be
320 if (!m_watcher
->Remove(wxFileName::DirName(path
)))
322 wxLogError("Error removing '%s' from watched paths", path
);
326 m_filesList
->DeleteItem(idx
);
330 void MyFrame::OnFileSystemEvent(wxFileSystemWatcherEvent
& event
)
332 // TODO remove when code is rock-solid
333 wxLogDebug(wxTRACE_FSWATCHER
, "*** %s ***", event
.ToString());
338 static wxString
GetFSWEventChangeTypeName(int changeType
)
342 case wxFSW_EVENT_CREATE
:
344 case wxFSW_EVENT_DELETE
:
346 case wxFSW_EVENT_RENAME
:
348 case wxFSW_EVENT_MODIFY
:
350 case wxFSW_EVENT_ACCESS
:
354 return "INVALID_TYPE";
357 void MyFrame::LogEvent(const wxFileSystemWatcherEvent
& event
)
359 wxString entry
= wxString::Format(LOG_FORMAT
+ "\n",
360 GetFSWEventChangeTypeName(event
.GetChangeType()),
361 event
.GetPath().GetFullPath(),
362 event
.GetNewPath().GetFullPath());
363 m_evtConsole
->AppendText(entry
);