/* $Id$ */ /* * Cantus Tag Editor * Copyright © 2002-2004 by Samuel Abels * Copyright © 2007 by Tim Huetz * * 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 **/ #ifdef HAVE_CONFIG_H # include #endif #include //#define _DEBUG_ /****************************************************************************** * Constructor/Destructor ******************************************************************************/ /* Constructor. */ FileInfo::FileInfo(std::string pfilename) { g_assert(pfilename != ""); real_filename = pfilename; edited_filename = pfilename; real_hash = cantushash_create(); edited_hash = cantushash_create(); stat(real_filename.c_str(), &filestat); cantushash_set_char(real_hash, "File:Name", real_filename.c_str()); cantushash_set_char(edited_hash, "File:Name", edited_filename.c_str()); } /* Destructor. */ FileInfo::~FileInfo(void) { mutex.lock(); CantusHash *hash = NULL; cantushash_destroy(real_hash); cantushash_destroy(edited_hash); while (hash = history.back()) { cantushash_destroy(hash); history.pop_back(); } while (hash = future.back()) { cantushash_destroy(hash); future.pop_back(); } mutex.unlock(); } /****************************************************************************** * Public ******************************************************************************/ /* Forces the file to be re-stated. */ int FileInfo::restat(void) { return stat(real_filename.c_str(), &filestat); } /* Returns the inode number of the file, or < 0 on an error. */ glong FileInfo::get_inode(void) { // Fixme: Handle stat failure! return filestat.st_ino; } /* Read all file informations into the real hash using the given function. * Returns an error code < 0, or 0 on success. */ gint FileInfo::read(const ReadFunc readfunc) { mutex.lock(); #ifdef _DEBUG_ std::cout << "FileInfo::read(): Called on " << get_filename() << ".\n"; #endif g_assert(readfunc != NULL); future_clear(); gint err = readfunc(get_filename(), real_hash); cantushash_destroy(edited_hash); edited_hash = cantushash_duplicate(real_hash); signal_read_finished(this); mutex.unlock(); return err; } /* Write all file informations from the real hash to the file system, using * the given function. * Returns an error code < 0, or 0 on success. */ gint FileInfo::write(const WriteFunc writefunc) { #ifdef _DEBUG_ mutex.lock(); std::cout << "FileInfo::write(): Called on " << get_filename() << ".\n"; mutex.unlock(); #endif g_assert(writefunc != NULL); this->commit(); mutex.lock(); const gchar *name = cantushash_get_char(real_hash, "File:Name"); gint err = writefunc(name, real_hash); signal_write_finished(this); mutex.unlock(); return err; } /* Returns a pointer to the file's "edited_hash". Make sure to "lock()" when you * do this! */ CantusHash *FileInfo::get_edited_hash(void) { return edited_hash; } /* Lock the object from being accessed. */ void FileInfo::lock(void) { mutex.lock(); } /* Unlock the object so that it can be accessed. */ void FileInfo::unlock(void) { mutex.unlock(); } /* Returns the filename from the real hash. Make sure to "lock()" when you do * this! */ const gchar *FileInfo::get_filename(void) { return real_filename.c_str(); } /* Returns the filename from the edited hash. Make sure to "lock()" when you do * this! */ const gchar *FileInfo::get_edited_filename(void) { edited_filename = cantushash_get_char(edited_hash, "File:Name"); return edited_filename.c_str(); } /* Move the "real hash" onto an "UNDO" stack. Then, copy the edited hash into * the new real hash. Also, clear the "REDO" stack. */ void FileInfo::commit(void) { mutex.lock(); #ifdef _DEBUG_ printf("FileInfo::commit(): Called on %s.\n", get_filename()); #endif CantusHash *copy = cantushash_duplicate(edited_hash); this->history_push(real_hash); real_hash = copy; mutex.unlock(); } /* Copy the real hash into the edited hash. */ void FileInfo::revert(void) { mutex.lock(); CantusHash *old = edited_hash; edited_hash = cantushash_duplicate(real_hash); cantushash_destroy(old); mutex.unlock(); } /* Push the edited hash onto the "REDO" stack. Then, pop the last item from * the "UNDO" stack into the edited hash. */ gboolean FileInfo::undo(void) { mutex.lock(); CantusHash *from_history = this->history_pop(); if (!from_history) { mutex.unlock(); return FALSE; } this->future_push(edited_hash); edited_hash = from_history; mutex.unlock(); return TRUE; } /* Push the edited hash onto the "UNDO" stack. Then, pop the last item from * the "REDO" stack into the edited hash. */ gboolean FileInfo::redo(void) { mutex.lock(); CantusHash *from_future = this->future_pop(); if (!from_future) { mutex.unlock(); return FALSE; } this->history_push(edited_hash); edited_hash = from_future; mutex.unlock(); return TRUE; } /****************************************************************************** * Private ******************************************************************************/ /* Push something to the history (for UNDO). */ void FileInfo::history_push(CantusHash *hash) { #ifdef _DEBUG_ printf("FileInfo::history_push(): Called.\n"); #endif history.push_front(hash); if (history.size() <= FILEINFO_HISTORY_LEN) return; if (history.back()) cantushash_destroy(history.back()); history.pop_back(); } /* Get something from the history (for UNDO). */ CantusHash *FileInfo::history_pop(void) { #ifdef _DEBUG_ printf("FileInfo::history_pop(): Called.\n"); #endif CantusHash *popped = history.front(); if (!popped) return NULL; history.pop_front(); return popped; } /* Get something to the future (for REDO). */ void FileInfo::future_push(CantusHash *hash) { #ifdef _DEBUG_ printf("FileInfo::future_push(): Called.\n"); #endif future.push_front(hash); if (future.size() <= FILEINFO_HISTORY_LEN) return; if (future.back()) cantushash_destroy(future.back()); future.pop_back(); } /* Get something from the future (for REDO). */ CantusHash *FileInfo::future_pop(void) { #ifdef _DEBUG_ printf("FileInfo::future_pop(): Called.\n"); #endif CantusHash *popped = future.front(); if (!popped) return NULL; future.pop_front(); return popped; } /* Clear the future (for REDO). */ void FileInfo::future_clear(void) { #ifdef _DEBUG_ printf("FileInfo::future_clear(): Called.\n"); #endif future.clear(); }