[gnote] Add NoteDirectoryWatcher add-in
- From: Aurimas Äernius <aurimasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnote] Add NoteDirectoryWatcher add-in
- Date: Thu, 5 Jul 2012 20:31:20 +0000 (UTC)
commit 696b6b2125e1d121358e3f84f2dceecd307b2ee7
Author: Aurimas Äernius <aurisc4 gmail com>
Date: Thu Jul 5 23:28:46 2012 +0300
Add NoteDirectoryWatcher add-in
An add-in for monitoring external note directory modifications.
configure.ac | 1 +
po/POTFILES.in | 1 +
src/addins/Makefile.am | 1 +
src/addins/notedirectorywatcher/Makefile.am | 9 +
.../notedirectorywatcherapplicationaddin.cpp | 319 ++++++++++++++++++++
.../notedirectorywatcherapplicationaddin.hpp | 94 ++++++
6 files changed, 425 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 3720a32..0f09770 100644
--- a/configure.ac
+++ b/configure.ac
@@ -169,6 +169,7 @@ src/addins/exporttohtml/Makefile
src/addins/filesystemsyncservice/Makefile
src/addins/fixedwidth/Makefile
src/addins/inserttimestamp/Makefile
+src/addins/notedirectorywatcher/Makefile
src/addins/noteoftheday/Makefile
src/addins/printnotes/Makefile
src/addins/replacetitle/Makefile
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 811e376..5ce665e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -11,6 +11,7 @@ src/addins/fixedwidth/fixedwidthmenuitem.cpp
src/addins/fixedwidth/fixedwidthnoteaddin.cpp
src/addins/inserttimestamp/inserttimestampnoteaddin.cpp
src/addins/inserttimestamp/inserttimestamppreferences.cpp
+src/addins/notedirectorywatcher/notedirectorywatcherapplicationaddin.cpp
src/addins/noteoftheday/noteofthedayapplicationaddin.cpp
src/addins/noteoftheday/noteoftheday.cpp
src/addins/noteoftheday/noteofthedaypreferences.cpp
diff --git a/src/addins/Makefile.am b/src/addins/Makefile.am
index 01dee7d..4dc3f08 100644
--- a/src/addins/Makefile.am
+++ b/src/addins/Makefile.am
@@ -7,6 +7,7 @@ SUBDIRS = backlinks \
filesystemsyncservice \
fixedwidth \
inserttimestamp \
+ notedirectorywatcher \
noteoftheday \
printnotes \
replacetitle \
diff --git a/src/addins/notedirectorywatcher/Makefile.am b/src/addins/notedirectorywatcher/Makefile.am
new file mode 100644
index 0000000..19bfb34
--- /dev/null
+++ b/src/addins/notedirectorywatcher/Makefile.am
@@ -0,0 +1,9 @@
+
+include $(builddir)/../addins.mk
+
+addinsdir = $(ADDINSDIR)
+addins_LTLIBRARIES = notedirectorywatcher.la
+
+
+notedirectorywatcher_la_SOURCES = notedirectorywatcherapplicationaddin.hpp notedirectorywatcherapplicationaddin.cpp \
+ $(NULL)
diff --git a/src/addins/notedirectorywatcher/notedirectorywatcherapplicationaddin.cpp b/src/addins/notedirectorywatcher/notedirectorywatcherapplicationaddin.cpp
new file mode 100644
index 0000000..b39fd4b
--- /dev/null
+++ b/src/addins/notedirectorywatcher/notedirectorywatcherapplicationaddin.cpp
@@ -0,0 +1,319 @@
+/*
+ * gnote
+ *
+ * Copyright (C) 2012 Aurimas Cernius
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <fstream>
+
+#include <glibmm/i18n.h>
+
+#include "debug.hpp"
+#include "gnote.hpp"
+#include "notedirectorywatcherapplicationaddin.hpp"
+#include "notemanager.hpp"
+#include "sharp/files.hpp"
+#include "sharp/string.hpp"
+
+
+namespace notedirectorywatcher {
+
+NoteDirectoryWatcherModule::NoteDirectoryWatcherModule()
+{
+ ADD_INTERFACE_IMPL(NoteDirectoryWatcherApplicationAddin);
+}
+
+const char * NoteDirectoryWatcherModule::id() const
+{
+ return "NoteDirectoryWatcherAddin";
+}
+
+const char * NoteDirectoryWatcherModule::name() const
+{
+ return _("Note Directory Watcher");
+}
+
+const char * NoteDirectoryWatcherModule::description() const
+{
+ return _("Watch your Gnote note directory for changes to your notes.");
+}
+
+const char * NoteDirectoryWatcherModule::authors() const
+{
+ return _("Aurimas Äernius and Tomboy original authors");
+}
+
+int NoteDirectoryWatcherModule::category() const
+{
+ return gnote::ADDIN_CATEGORY_TOOLS;
+}
+
+const char * NoteDirectoryWatcherModule::version() const
+{
+ return "0.1";
+}
+
+
+
+
+NoteDirectoryWatcherApplicationAddin::NoteDirectoryWatcherApplicationAddin()
+ : m_initialized(false)
+{
+}
+
+void NoteDirectoryWatcherApplicationAddin::initialize()
+{
+ gnote::NoteManager & note_manager = gnote::Gnote::obj().default_note_manager();
+ std::string note_path = note_manager.get_notes_dir();
+ note_manager.signal_note_saved
+ .connect(sigc::mem_fun(*this, &NoteDirectoryWatcherApplicationAddin::handle_note_saved));
+
+ Glib::RefPtr<Gio::File> file = Gio::File::create_for_path(note_path);
+ m_file_system_watcher = file->monitor_directory();
+
+ m_file_system_watcher->signal_changed()
+ .connect(sigc::mem_fun(*this, &NoteDirectoryWatcherApplicationAddin::handle_file_system_change_event));
+
+ m_initialized = true;
+}
+
+void NoteDirectoryWatcherApplicationAddin::shutdown()
+{
+ m_file_system_watcher->cancel();
+ m_initialized = false;
+}
+
+bool NoteDirectoryWatcherApplicationAddin::initialized()
+{
+ return m_initialized;
+}
+
+void NoteDirectoryWatcherApplicationAddin::handle_note_saved(const gnote::Note::Ptr & note)
+{
+ m_note_save_times[note->id()] = sharp::DateTime::now();
+}
+
+void NoteDirectoryWatcherApplicationAddin::handle_file_system_change_event(
+ const Glib::RefPtr<Gio::File> & file, const Glib::RefPtr<Gio::File> &, Gio::FileMonitorEvent event_type)
+{
+ switch(event_type) {
+ case Gio::FILE_MONITOR_EVENT_CHANGED:
+ case Gio::FILE_MONITOR_EVENT_DELETED:
+ case Gio::FILE_MONITOR_EVENT_CREATED:
+ case Gio::FILE_MONITOR_EVENT_MOVED:
+ break;
+ default:
+ return;
+ }
+
+ std::string note_id = get_id(file->get_path());
+
+ DBG_OUT("NoteDirectoryWatcher: %s has %d (note_id=%s)", file->get_path().c_str(), int(event_type), note_id.c_str());
+
+ // Record that the file has been added/changed/deleted. Adds/changes trump
+ // deletes. Record the date.
+ m_lock.lock();
+ try {
+ std::map<std::string, NoteFileChangeRecord>::iterator record = m_file_change_records.find(note_id);
+ if(record == m_file_change_records.end()) {
+ m_file_change_records[note_id] = NoteFileChangeRecord();
+ record = m_file_change_records.find(note_id);
+ }
+
+ if(event_type == Gio::FILE_MONITOR_EVENT_CHANGED) {
+ record->second.changed = true;
+ record->second.deleted = false;
+ }
+ else if(event_type == Gio::FILE_MONITOR_EVENT_CREATED) {
+ record->second.changed = true;
+ record->second.deleted = false;
+ }
+ else if(event_type == Gio::FILE_MONITOR_EVENT_MOVED) {
+ record->second.changed = true;
+ record->second.deleted = false;
+ }
+ else if(event_type == Gio::FILE_MONITOR_EVENT_DELETED) {
+ if(!record->second.changed) {
+ record->second.deleted = true;
+ }
+ }
+
+ record->second.last_change = sharp::DateTime::now();
+ }
+ catch(...)
+ {}
+ m_lock.unlock();
+
+ Glib::RefPtr<Glib::TimeoutSource> timeout = Glib::TimeoutSource::create(5000);
+ timeout->connect(sigc::mem_fun(*this, &NoteDirectoryWatcherApplicationAddin::handle_timeout));
+ timeout->attach();
+}
+
+std::string NoteDirectoryWatcherApplicationAddin::get_id(const std::string & path)
+{
+ std::string dir_separator;
+ dir_separator += G_DIR_SEPARATOR;
+ int last_slash = sharp::string_last_index_of(path, std::string(dir_separator));
+ int first_period = sharp::string_index_of(path, ".", last_slash);
+
+ return path.substr(last_slash + 1, first_period - last_slash - 1);
+}
+
+bool NoteDirectoryWatcherApplicationAddin::handle_timeout()
+{
+ m_lock.lock();
+ try {
+ std::vector<std::string> keysToRemove(m_file_change_records.size());
+
+ for(std::map<std::string, NoteFileChangeRecord>::iterator iter = m_file_change_records.begin();
+ iter != m_file_change_records.end(); ++iter) {
+ DBG_OUT("NoteDirectoryWatcher: Handling (timeout) %s", iter->first.c_str());
+
+ // Check that Note.Saved event didn't occur within 3 seconds of last write
+ if(m_note_save_times.find(iter->first) != m_note_save_times.end() &&
+ std::abs((m_note_save_times[iter->first] - iter->second.last_change).total_seconds()) <= 3) {
+ DBG_OUT("NoteDirectoryWatcher: Ignoring (timeout) because it was probably a Gnote write");
+ keysToRemove.push_back(iter->first);
+ continue;
+ }
+ // TODO: Take some actions to clear note_save_times? Not a large structure...
+
+ sharp::DateTime last_change(iter->second.last_change);
+ if(sharp::DateTime::now() > last_change.add_seconds(4)) {
+ if(iter->second.deleted) {
+ delete_note(iter->first);
+ }
+ else {
+ add_or_update_note(iter->first);
+ }
+
+ keysToRemove.push_back(iter->first);
+ }
+ }
+
+ for(std::vector<std::string>::iterator note_id = keysToRemove.begin(); note_id != keysToRemove.end(); ++note_id) {
+ m_file_change_records.erase(*note_id);
+ }
+ }
+ catch(...)
+ {}
+ m_lock.unlock();
+
+ return false;
+}
+
+void NoteDirectoryWatcherApplicationAddin::delete_note(const std::string & note_id)
+{
+ DBG_OUT("NoteDirectoryWatcher: deleting %s because file deleted.", note_id.c_str());
+
+ std::string note_uri = make_uri(note_id);
+
+ gnote::Note::Ptr note_to_delete = gnote::Gnote::obj().default_note_manager().find_by_uri(note_uri);
+ if(note_to_delete != 0) {
+ gnote::Gnote::obj().default_note_manager().delete_note(note_to_delete);
+ }
+ else {
+ DBG_OUT("notedirectorywatcher: did not delete %s because note not found.", note_id.c_str());
+ }
+}
+
+void NoteDirectoryWatcherApplicationAddin::add_or_update_note(const std::string & note_id)
+{
+ std::string note_path = Glib::build_filename(
+ gnote::Gnote::obj().default_note_manager().get_notes_dir(), note_id + ".note");
+ if (!sharp::file_exists(note_path)) {
+ DBG_OUT("NoteDirectoryWatcher: Not processing update of %s because file does not exist.", note_path.c_str());
+ return;
+ }
+
+ std::string noteXml;
+ try {
+ std::ifstream reader;
+ reader.exceptions(std::ios_base::badbit);
+ reader.open(note_path.c_str());
+ std::string line;
+ while(std::getline(reader, line)) {
+ noteXml += line + '\n';
+ }
+ reader.close();
+ }
+ catch(std::ios::failure & e) {
+ ERR_OUT("NoteDirectoryWatcher: Update aborted, error reading %s: %s", note_path.c_str(), e.what());
+ return;
+ }
+
+ if(noteXml == "") {
+ DBG_OUT("NoteDirectoryWatcher: Update aborted, %s had no contents.", note_path.c_str());
+ return;
+ }
+
+ std::string note_uri = make_uri(note_id);
+
+ gnote::Note::Ptr note = gnote::Gnote::obj().default_note_manager().find_by_uri(note_uri);
+
+ bool is_new_note = false;
+
+ if(note == 0) {
+ is_new_note = true;
+ DBG_OUT("NoteDirectoryWatcher: Adding %s because file changed.", note_id.c_str());
+
+ std::string title;
+ Glib::RefPtr<Glib::Regex> regex = Glib::Regex::create("<title>([^<]+)</title>", Glib::REGEX_MULTILINE);
+ Glib::MatchInfo match_info;
+ if(regex->match(noteXml, match_info)) {
+ title = match_info.fetch(1);
+ }
+ else {
+ ERR_OUT("NoteDirectoryWatcher: Error reading note title from %s", note_path.c_str());
+ return;
+ }
+
+ try {
+ note = gnote::Gnote::obj().default_note_manager().create_with_guid(title, note_id);
+ if(note == 0) {
+ ERR_OUT("NoteDirectoryWatcher: Unknown error creating note from %s", note_path.c_str());
+ return;
+ }
+ }
+ catch(std::exception & e) {
+ ERR_OUT("NoteDirectoryWatcher: Error creating note from %s: %s", note_path.c_str(), e.what());
+ return;
+ }
+ }
+
+ if(is_new_note) {
+ DBG_OUT("NoteDirectoryWatcher: Updating %s because file changed.", note_id.c_str());
+ }
+ try {
+ note->load_foreign_note_xml(noteXml, gnote::CONTENT_CHANGED);
+ }
+ catch(std::exception & e) {
+ ERR_OUT("NoteDirectoryWatcher: Update aborted, error parsing %s: %s", note_path.c_str(), e.what());
+ if(is_new_note) {
+ gnote::Gnote::obj().default_note_manager().delete_note(note);
+ }
+ }
+}
+
+std::string NoteDirectoryWatcherApplicationAddin::make_uri(const std::string & note_id)
+{
+ return "note://gnote/" + note_id;
+}
+
+
+}
+
diff --git a/src/addins/notedirectorywatcher/notedirectorywatcherapplicationaddin.hpp b/src/addins/notedirectorywatcher/notedirectorywatcherapplicationaddin.hpp
new file mode 100644
index 0000000..8aabfde
--- /dev/null
+++ b/src/addins/notedirectorywatcher/notedirectorywatcherapplicationaddin.hpp
@@ -0,0 +1,94 @@
+/*
+ * gnote
+ *
+ * Copyright (C) 2012 Aurimas Cernius
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NOTE_DIRECTORY_WATCHER_APPLICATION_ADDIN_
+#define _NOTE_DIRECTORY_WATCHER_APPLICATION_ADDIN_
+
+
+#include <map>
+
+#include <glibmm/threads.h>
+#include <giomm/filemonitor.h>
+
+#include "applicationaddin.hpp"
+#include "note.hpp"
+#include "sharp/dynamicmodule.hpp"
+
+
+namespace notedirectorywatcher {
+
+class NoteDirectoryWatcherModule
+ : public sharp::DynamicModule
+{
+public:
+ NoteDirectoryWatcherModule();
+ virtual const char * id() const;
+ virtual const char * name() const;
+ virtual const char * description() const;
+ virtual const char * authors() const;
+ virtual int category() const;
+ virtual const char * version() const;
+};
+
+
+DECLARE_MODULE(NoteDirectoryWatcherModule);
+
+struct NoteFileChangeRecord
+{
+ sharp::DateTime last_change;
+ bool deleted;
+ bool changed;
+};
+
+
+class NoteDirectoryWatcherApplicationAddin
+ : public gnote::ApplicationAddin
+{
+public:
+ static NoteDirectoryWatcherApplicationAddin *create()
+ {
+ return new NoteDirectoryWatcherApplicationAddin;
+ }
+ virtual void initialize();
+ virtual void shutdown();
+ virtual bool initialized();
+private:
+ static std::string get_id(const std::string & path);
+ static std::string make_uri(const std::string & note_id);
+
+ NoteDirectoryWatcherApplicationAddin();
+ void handle_note_saved(const gnote::Note::Ptr &);
+ void handle_file_system_change_event(const Glib::RefPtr<Gio::File> & file,
+ const Glib::RefPtr<Gio::File> & other_file,
+ Gio::FileMonitorEvent event_type);
+ bool handle_timeout();
+ void delete_note(const std::string & note_id);
+ void add_or_update_note(const std::string & note_id);
+
+ Glib::RefPtr<Gio::FileMonitor> m_file_system_watcher;
+
+ std::map<std::string, NoteFileChangeRecord> m_file_change_records;
+ std::map<std::string, sharp::DateTime> m_note_save_times;
+ bool m_initialized;
+ Glib::Threads::Mutex m_lock;
+};
+
+}
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]