5276b0a53c
Use wxDELETE[A]() functions which automatically NULL out their arguments after deleting them instead of doing it manually. Closes #9685. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64656 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
363 lines
11 KiB
C++
363 lines
11 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: samples/fswatcher/fswatcher.cpp
|
|
// Purpose: wxFileSystemWatcher sample
|
|
// Author: Bartosz Bekier
|
|
// Created: 2009-06-27
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) Bartosz Bekier
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif
|
|
|
|
#ifndef __WXMSW__
|
|
#include "../sample.xpm"
|
|
#endif
|
|
|
|
#include "wx/fswatcher.h"
|
|
#include "wx/listctrl.h"
|
|
|
|
// Define a new frame type: this is going to be our main frame
|
|
class MyFrame : public wxFrame
|
|
{
|
|
public:
|
|
MyFrame(const wxString& title);
|
|
virtual ~MyFrame();
|
|
|
|
private:
|
|
// file system watcher creation
|
|
void OnEventLoopEnter();
|
|
void CreateWatcher();
|
|
|
|
// event handlers
|
|
void OnClear(wxCommandEvent& WXUNUSED(event)) { m_evtConsole->Clear(); }
|
|
void OnQuit(wxCommandEvent& WXUNUSED(event)) { Close(true); }
|
|
void OnWatch(wxCommandEvent& event);
|
|
void OnAbout(wxCommandEvent& event);
|
|
|
|
void OnAdd(wxCommandEvent& event);
|
|
void OnRemove(wxCommandEvent& event);
|
|
|
|
void OnFileSystemEvent(wxFileSystemWatcherEvent& event);
|
|
void LogEvent(const wxFileSystemWatcherEvent& event);
|
|
|
|
wxTextCtrl *m_evtConsole; // events console
|
|
wxListView *m_filesList; // list of watched paths
|
|
wxFileSystemWatcher* m_watcher; // file system watcher
|
|
|
|
friend class MyApp;
|
|
|
|
const static wxString LOG_FORMAT; // how to format events
|
|
};
|
|
|
|
const wxString MyFrame::LOG_FORMAT = " %-12s %-36s %-36s";
|
|
|
|
// Define a new application type, each program should derive a class from wxApp
|
|
class MyApp : public wxApp
|
|
{
|
|
public:
|
|
// 'Main program' equivalent: the program execution "starts" here
|
|
virtual bool OnInit()
|
|
{
|
|
wxLog::AddTraceMask("EventSource");
|
|
wxLog::AddTraceMask(wxTRACE_FSWATCHER);
|
|
|
|
// create the main application window
|
|
m_frame = new MyFrame("File System Watcher wxWidgets App");
|
|
|
|
// If we returned false here, the application would exit immediately.
|
|
return true;
|
|
}
|
|
|
|
// create the file system watcher here, because it needs an active loop
|
|
virtual void OnEventLoopEnter(wxEventLoopBase* WXUNUSED(loop))
|
|
{
|
|
m_frame->OnEventLoopEnter();
|
|
}
|
|
|
|
private:
|
|
MyFrame *m_frame;
|
|
};
|
|
|
|
// Create a new application object: this macro will allow wxWidgets to create
|
|
// the application object during program execution (it's better than using a
|
|
// static object for many reasons) and also declares the accessor function
|
|
// wxGetApp() which will return the reference of the right type (i.e. MyApp and
|
|
// not wxApp)
|
|
IMPLEMENT_APP(MyApp)
|
|
|
|
|
|
// ============================================================================
|
|
// implementation
|
|
// ============================================================================
|
|
|
|
// frame constructor
|
|
MyFrame::MyFrame(const wxString& title)
|
|
: wxFrame(NULL, wxID_ANY, title),
|
|
m_watcher(NULL)
|
|
{
|
|
SetIcon(wxICON(sample));
|
|
|
|
// IDs for menu and buttons
|
|
enum
|
|
{
|
|
MENU_ID_QUIT = wxID_EXIT,
|
|
MENU_ID_CLEAR = wxID_CLEAR,
|
|
MENU_ID_WATCH = 101,
|
|
|
|
BTN_ID_ADD = 200,
|
|
BTN_ID_REMOVE = 201,
|
|
};
|
|
|
|
// ================================================================
|
|
// menu
|
|
|
|
// create a menu bar
|
|
wxMenu *menuFile = new wxMenu;
|
|
menuFile->Append(MENU_ID_CLEAR, "&Clear log\tCtrl-L");
|
|
menuFile->AppendSeparator();
|
|
menuFile->Append(MENU_ID_QUIT, "E&xit\tAlt-X", "Quit this program");
|
|
|
|
// "Watch" menu
|
|
wxMenu *menuMon = new wxMenu;
|
|
wxMenuItem* it = menuMon->AppendCheckItem(MENU_ID_WATCH, "&Watch\tCtrl-W");
|
|
// started by default, because file system watcher is started by default
|
|
it->Check(true);
|
|
|
|
// the "About" item should be in the help menu
|
|
wxMenu *menuHelp = new wxMenu;
|
|
menuHelp->Append(wxID_ABOUT, "&About...\tF1", "Show about dialog");
|
|
|
|
// now append the freshly created menu to the menu bar...
|
|
wxMenuBar *menuBar = new wxMenuBar();
|
|
menuBar->Append(menuFile, "&File");
|
|
menuBar->Append(menuMon, "&Watch");
|
|
menuBar->Append(menuHelp, "&Help");
|
|
|
|
// ... and attach this menu bar to the frame
|
|
SetMenuBar(menuBar);
|
|
|
|
// ================================================================
|
|
// upper panel
|
|
|
|
// panel
|
|
wxPanel *panel = new wxPanel(this);
|
|
wxSizer *panelSizer = new wxGridSizer(2);
|
|
wxBoxSizer *leftSizer = new wxBoxSizer(wxVERTICAL);
|
|
|
|
// label
|
|
wxStaticText* label = new wxStaticText(panel, wxID_ANY, "Watched paths");
|
|
leftSizer->Add(label, wxSizerFlags().Center().Border(wxALL));
|
|
|
|
// list of files
|
|
m_filesList = new wxListView(panel, wxID_ANY, wxPoint(-1,-1),
|
|
wxSize(300,200), wxLC_LIST | wxLC_SINGLE_SEL);
|
|
leftSizer->Add(m_filesList, wxSizerFlags(1).Expand());
|
|
|
|
// buttons
|
|
wxButton* buttonAdd = new wxButton(panel, BTN_ID_ADD, "&Add");
|
|
wxButton* buttonRemove = new wxButton(panel, BTN_ID_REMOVE, "&Remove");
|
|
wxSizer *btnSizer = new wxGridSizer(2);
|
|
btnSizer->Add(buttonAdd, wxSizerFlags().Center().Border(wxALL));
|
|
btnSizer->Add(buttonRemove, wxSizerFlags().Center().Border(wxALL));
|
|
|
|
// and put it all together
|
|
leftSizer->Add(btnSizer, wxSizerFlags(0).Expand());
|
|
panelSizer->Add(leftSizer, wxSizerFlags(1).Expand());
|
|
panel->SetSizerAndFit(panelSizer);
|
|
|
|
// ================================================================
|
|
// lower panel
|
|
|
|
wxTextCtrl *headerText = new wxTextCtrl(this, wxID_ANY, "",
|
|
wxDefaultPosition, wxDefaultSize,
|
|
wxTE_READONLY);
|
|
wxString h = wxString::Format(LOG_FORMAT, "event", "path", "new path");
|
|
headerText->SetValue(h);
|
|
|
|
// event console
|
|
m_evtConsole = new wxTextCtrl(this, wxID_ANY, "",
|
|
wxDefaultPosition, wxSize(200,200),
|
|
wxTE_MULTILINE|wxTE_READONLY|wxHSCROLL);
|
|
|
|
// set monospace font to have output in nice columns
|
|
wxFont font(9, wxFONTFAMILY_TELETYPE,
|
|
wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
|
|
headerText->SetFont(font);
|
|
m_evtConsole->SetFont(font);
|
|
|
|
// ================================================================
|
|
// laying out whole frame
|
|
|
|
wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
|
|
sizer->Add(panel, wxSizerFlags(1).Expand());
|
|
sizer->Add(headerText, wxSizerFlags().Expand());
|
|
sizer->Add(m_evtConsole, wxSizerFlags(1).Expand());
|
|
SetSizerAndFit(sizer);
|
|
|
|
// set size and position on screen
|
|
SetSize(800, 600);
|
|
CentreOnScreen();
|
|
|
|
// ================================================================
|
|
// event handlers & show
|
|
|
|
// menu
|
|
Connect(MENU_ID_CLEAR, wxEVT_COMMAND_MENU_SELECTED,
|
|
wxCommandEventHandler(MyFrame::OnClear));
|
|
Connect(MENU_ID_QUIT, wxEVT_COMMAND_MENU_SELECTED,
|
|
wxCommandEventHandler(MyFrame::OnQuit));
|
|
Connect(MENU_ID_WATCH, wxEVT_COMMAND_MENU_SELECTED,
|
|
wxCommandEventHandler(MyFrame::OnWatch));
|
|
Connect(wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED,
|
|
wxCommandEventHandler(MyFrame::OnAbout));
|
|
|
|
// buttons
|
|
Connect(BTN_ID_ADD, wxEVT_COMMAND_BUTTON_CLICKED,
|
|
wxCommandEventHandler(MyFrame::OnAdd));
|
|
Connect(BTN_ID_REMOVE, wxEVT_COMMAND_BUTTON_CLICKED,
|
|
wxCommandEventHandler(MyFrame::OnRemove));
|
|
|
|
// and show itself (the frames, unlike simple controls, are not shown when
|
|
// created initially)
|
|
Show(true);
|
|
}
|
|
|
|
MyFrame::~MyFrame()
|
|
{
|
|
delete m_watcher;
|
|
}
|
|
|
|
void MyFrame::OnEventLoopEnter()
|
|
{
|
|
if (m_watcher)
|
|
return;
|
|
|
|
CreateWatcher();
|
|
Connect(wxEVT_FSWATCHER,
|
|
wxFileSystemWatcherEventHandler(MyFrame::OnFileSystemEvent));
|
|
}
|
|
|
|
void MyFrame::CreateWatcher()
|
|
{
|
|
wxCHECK_RET(!m_watcher, "Watcher already initialized");
|
|
m_watcher = new wxFileSystemWatcher();
|
|
m_watcher->SetOwner(this);
|
|
}
|
|
|
|
// ============================================================================
|
|
// event handlers
|
|
// ============================================================================
|
|
|
|
void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
wxMessageBox("Demonstrates the usage of file system watcher, "
|
|
"the wxWidgets monitoring system notifying you of "
|
|
"changes done to your files.\n"
|
|
"(c) 2009 Bartosz Bekier\n",
|
|
"About wxWidgets File System Watcher Sample",
|
|
wxOK | wxICON_INFORMATION, this);
|
|
}
|
|
|
|
void MyFrame::OnWatch(wxCommandEvent& event)
|
|
{
|
|
wxLogDebug("%s start=%d", __WXFUNCTION__, event.IsChecked());
|
|
|
|
if (event.IsChecked())
|
|
{
|
|
wxCHECK_RET(!m_watcher, "Watcher already initialized");
|
|
CreateWatcher();
|
|
}
|
|
else
|
|
{
|
|
wxCHECK_RET(m_watcher, "Watcher not initialized");
|
|
m_filesList->DeleteAllItems();
|
|
wxDELETE(m_watcher);
|
|
}
|
|
}
|
|
|
|
void MyFrame::OnAdd(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
wxCHECK_RET(m_watcher, "Watcher not initialized");
|
|
|
|
// TODO account for adding the files as well
|
|
const wxString& dir = wxDirSelector("Choose a folder to watch", "",
|
|
wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
|
|
if ( dir.empty() )
|
|
return;
|
|
|
|
wxLogDebug("Adding directory: '%s'", dir);
|
|
|
|
if (!m_watcher->Add(wxFileName::DirName(dir), wxFSW_EVENT_ALL))
|
|
{
|
|
wxLogError("Error adding '%s' to watched paths", dir);
|
|
}
|
|
else
|
|
{
|
|
m_filesList->InsertItem(m_filesList->GetItemCount(), dir);
|
|
}
|
|
}
|
|
|
|
void MyFrame::OnRemove(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
wxCHECK_RET(m_watcher, "Watcher not initialized");
|
|
long idx = m_filesList->GetFirstSelected();
|
|
if (idx == -1)
|
|
return;
|
|
|
|
wxString path = m_filesList->GetItemText(idx);
|
|
|
|
// TODO we know it is a dir, but it doesn't have to be
|
|
if (!m_watcher->Remove(wxFileName::DirName(path)))
|
|
{
|
|
wxLogError("Error removing '%s' from watched paths", path);
|
|
}
|
|
else
|
|
{
|
|
m_filesList->DeleteItem(idx);
|
|
}
|
|
}
|
|
|
|
void MyFrame::OnFileSystemEvent(wxFileSystemWatcherEvent& event)
|
|
{
|
|
// TODO remove when code is rock-solid
|
|
wxLogDebug(wxTRACE_FSWATCHER, "*** %s ***", event.ToString());
|
|
LogEvent(event);
|
|
}
|
|
|
|
|
|
static wxString GetFSWEventChangeTypeName(int changeType)
|
|
{
|
|
switch (changeType)
|
|
{
|
|
case wxFSW_EVENT_CREATE:
|
|
return "CREATE";
|
|
case wxFSW_EVENT_DELETE:
|
|
return "DELETE";
|
|
case wxFSW_EVENT_RENAME:
|
|
return "RENAME";
|
|
case wxFSW_EVENT_MODIFY:
|
|
return "MODIFY";
|
|
case wxFSW_EVENT_ACCESS:
|
|
return "ACCESS";
|
|
}
|
|
|
|
return "INVALID_TYPE";
|
|
}
|
|
|
|
void MyFrame::LogEvent(const wxFileSystemWatcherEvent& event)
|
|
{
|
|
wxString entry = wxString::Format(LOG_FORMAT + "\n",
|
|
GetFSWEventChangeTypeName(event.GetChangeType()),
|
|
event.GetPath().GetFullPath(),
|
|
event.GetNewPath().GetFullPath());
|
|
m_evtConsole->AppendText(entry);
|
|
}
|