iso-profiles-settings/tromjaro/gnome/live-overlay/etc/skel/.local/share/gnome-shell/extensions/todo.txt@bart.libert.gmail.com/extension.js
2019-07-09 04:57:09 +03:00

952 lines
34 KiB
JavaScript

// This extension was developed by Bart Libert
//
// Based on code by :
// * Baptiste Saleil http://bsaleil.org/
// * Arnaud Bonatti https://github.com/Obsidien
//
// Licence: GPLv2+
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Main = imports.ui.main;
const Meta = imports.gi.Meta;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Extension = imports.misc.extensionUtils.getCurrentExtension();
const Errors = Extension.imports.errors;
const JsTextFile = Extension.imports.jsTextFile;
const Message = Extension.imports.messageDialog.MessageDialog;
const MultiButtonDialog = Extension.imports.multiButtonDialog;
const ScrollablePopupMenu = Extension.imports.scrollablePopupMenu.ScrollablePopupMenu;
const Settings = Extension.imports.settings.Settings;
const Shared = Extension.imports.sharedConstants;
const TodoMenuItem = Extension.imports.todoMenuItem.TodoMenuItem;
const TopBar = Extension.imports.topBar.TodoTopBar;
const Utils = Extension.imports.utils;
const Third = Extension.imports.third_party;
const Decorator = Third.logDecorator.logDecorator.LogDecorator;
const JsTodo = Third.jsTodoTxt.jsTodoTxt;
const JsTodoExtensions = Third.jsTodoTxt.jsTodoExtensions;
const Gettext = imports.gettext;
const _ = Gettext.domain('todotxt').gettext;
const schema = 'org.gnome.shell.extensions.TodoTxt';
const openKey = 'open-key';
let todoTxt;
const TodoTxtManager = new Lang.Class({
Name: 'TodoTxtManager',
Extends: PanelMenu.Button,
schema: null,
settings: null,
autoarchive: false,
tasks: null,
debugLevel: Shared.LOG_ERROR,
groupBy: null,
groupUngrouped: false,
monitor: null,
volumeMonitor: null,
linkMonitor: null,
decorator: null,
logger: null,
fileLoaded: false,
enabledExtensions: [],
keepOpenAfterNew: true,
insertTaskAtTop: false,
_init: function(logger) {
PanelMenu.Button.prototype._init.call(this, St.Align.START, 'todo.txt', true);
this.schema = schema;
this.logger = logger;
this._initSettings();
this._loadSettings();
this.logger.setLevel(this.debugLevel);
this.decorator = new Decorator();
this.decorator.setLogger(this.logger.flow);
this.popupMenu = new ScrollablePopupMenu(this.actor, St.Align.START, St.Side.TOP, logger);
this.decorator.addLoggingToNamespace(this.popupMenu);
this.setMenu(this.popupMenu);
this.tasks = [];
this.groupedTasksParameter = [];
this.groupedTasksParameter[Shared.NO_GROUPING] = '';
this.groupedTasksParameter[Shared.GROUP_BY_PROJECTS] = 'projects';
this.groupedTasksParameter[Shared.GROUP_BY_CONTEXTS] = 'contexts';
this.topbar = new TopBar({
initialText: '[...]',
logger: this.logger,
decorator: this.decorator,
taskInfoProvider: this,
settings: this.settings
});
this.decorator.addLoggingToNamespace(this.topbar);
this.topbar.update({
busy: true
});
this.actor.add_actor(this.topbar.actor);
this._installShortcuts();
this._refresh();
},
getNbOfUnarchivedTasks: function() {
if (this.tasks === null) {
return 0;
}
return this.tasks.length;
},
getNbOfUndoneTasks: function() {
let count = 0;
for (let i = 0, len = this.tasks.length; i < len; i++) {
if (!this.tasks[i].complete) {
count++;
}
}
return count;
},
getNbOfHiddenTasks: function() {
let count = 0;
for (let i = 0, len = this.tasks.length; i < len; i++) {
if (this.tasks[i].hidden) {
count++;
}
}
return count;
},
_createNewTaskEntry: function() {
this.newTask = new St.Entry({
name: 'newTaskEntry',
hint_text: _('New task...'),
track_hover: true,
can_focus: true
});
this.newTask.add_style_class_name('run-dialog-entry');
let tasksMenu = this.menu;
let entryNewTask = this.newTask.clutter_text;
entryNewTask.connect('key-press-event', Lang.bind(this, function(o, e) {
let symbol = e.get_key_symbol();
if ((symbol == Clutter.Return) || (symbol == Clutter.KP_Enter)) {
let text = o.get_text();
o.set_text('');
if (!this.keepOpenAfterNew) {
tasksMenu.close();
}
if (text === '') {
return;
}
this.topbar.update({
busy: true
});
let newTask = new JsTodo.TodoTxtItem(text, this.enabledExtensions);
this.decorator.addLoggingToNamespace(newTask);
this.addTask(newTask);
}
}));
},
_createTodoItem: function(task) {
if (task.hidden) {
return null;
}
let actions = {
doneAction: Lang.bind(this, function(task) {
this.topbar.update({
busy: true
});
this.completeTask(task);
}),
archiveAction: Lang.bind(this, function(task) {
this.topbar.update({
busy: true
});
this.archiveTask(task);
}),
deleteAction: Lang.bind(this, function(task) {
this.topbar.update({
busy: true
});
this.removeTask(task);
}),
editAction: Lang.bind(this, function(oldTask, newTask) {
this.modifyTask(oldTask, newTask, true);
}),
priorityAction: Lang.bind(this, function(task, up) {
this.topbar.update({
busy: true
});
this.modifyTaskPriority(task, up);
})
};
return new TodoMenuItem(task, this.settings, actions);
},
_initSettings: function() {
let params = {
settingsFile: Utils.getFirstValidChild(Extension, ['path', 'metadata.path']) +
'/settings.json',
schema: this.schema,
logger: this.logger
};
this.settings = new Settings(params);
},
_loadSettings: function() {
this.todofile = this.settings.get('todotxt-location');
this.donefile = this.settings.get('donetxt-location');
this.autoarchive = this.settings.get('auto-archive');
this.debugLevel = this.settings.get('debug-level');
this.groupBy = this.settings.get('group-by');
this.groupUngrouped = this.settings.get('group-ungrouped');
this.showNewTaskEntry = this.settings.get('show-new-task-entry');
this.addCreationDate = this.settings.get('add-creation-date');
this.showOpenInTextEditor = this.settings.get('show-open-in-text-editor');
this.priorityOnDone = this.settings.get('priority-on-done');
this.showNumberOfGroupElements = this.settings.get('show-number-of-group-elements');
this.hiddenExtension = this.settings.get('enable-hidden-extension');
this.keepOpenAfterNew = this.settings.get('keep-open-after-new');
this.insertTaskAtTop = (this.settings.get('task-insert-location') == Shared.TASK_INSERT_LOCATION_TOP);
},
_connectSettingsSignals: function() {
this.settings.registerForChange('auto-archive', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('todotxt-location', Lang.bind(this, this.onTodoFileChanged));
this.settings.registerForChange('donetxt-location', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('debug-level', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('group-by', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('group-ungrouped', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('priorities-markup', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('show-done-or-archive-button', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('show-delete-button', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('show-projects-label', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('show-contexts-label', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('show-new-task-entry', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('show-open-in-text-editor', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('style-priorities', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('add-creation-date', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('show-edit-button', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('show-priority-buttons', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('click-action', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('open-key', Lang.bind(this, this.onShortcutChanged));
this.settings.registerForChange('confirm-delete', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('url-color', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('custom-url-color', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('long-tasks-expansion-mode', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('truncate-long-tasks', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('long-tasks-max-width', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('long-tasks-ellipsize-mode', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('priority-on-done', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('show-number-of-group-elements', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('enable-hidden-extension', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('keep-open-after-new', Lang.bind(this, this.onParamChanged));
this.settings.registerForChange('task-insert-location', Lang.bind(this, this.onParamChanged));
},
_loadExtensions: function() {
this.enabledExtensions = [];
if (this.hiddenExtension) {
this.enabledExtensions.push(new JsTodoExtensions.HiddenExtension());
}
},
_refresh: function() {
// Clear
this.menu.removeAll();
this.menu.clearSection('top');
this.menu.clearSection('bottom');
let todoFile = null;
// Sync
try {
todoFile = new JsTextFile.JsTextFile(this.todofile, this.logger);
}
catch (exception) {
this.logger.info('File could not be read, showing \'no file\' menu');
this._createNoFileMenu('todo.txt');
return false;
}
this.decorator.addLoggingToNamespace(todoFile);
if (!todoFile.exists()) {
return false;
}
this._loadExtensions();
this._createTasksFromFile(todoFile.getLines());
this._createTasksMenu();
this.topbar.update();
if (!this.showNewTaskEntry && !this.showOpenInTextEditor) {
return true;
}
if (this.showNewTaskEntry) {
let section = 'bottom';
if (this.insertTaskAtTop === true) {
section = 'top';
}
let newTaskSection = new PopupMenu.PopupMenuSection();
this._createNewTaskEntry();
newTaskSection.actor.add_actor(this.newTask);
newTaskSection.actor.add_style_class_name('newTaskSection');
this.menu.addToSection(section, newTaskSection.actor);
this.menu.connect('open-state-changed', Lang.bind(this, function(open) {
if (open) {
this.newTask.grab_key_focus();
}
}));
}
if (this.showOpenInTextEditor) {
let editorSection = new PopupMenu.PopupMenuSection();
let editorButton = new PopupMenu.PopupMenuItem(_('Open todo.txt file in text editor'));
editorButton.connect('activate', Lang.bind(this, function(object, event) {
try {
Gio.AppInfo.launch_default_for_uri(GLib.filename_to_uri(this.todofile, null),
global.create_app_launch_context(event.get_time(), -1));
}
catch (exception) {
let message = new Message(_('Cannot open file'),
_(
'An error occured while trying to launch the default text editor: %(error)'
).replace('%(error)', exception.message));
message.open();
}
}));
editorSection.addMenuItem(editorButton);
this.menu.addToSection('bottom', editorSection.actor);
}
if (this.menu.isOpen) {
this.newTask.grab_key_focus();
}
return true;
},
_addTasksToMain: function(tasks) {
tasks.sort(this.sortByPriority);
for (let i = 0; i < tasks.length; i++) {
let item = this._createTodoItem(tasks[i]);
if (item !== null) {
this.menu.addMenuItem(item);
}
}
return;
},
_createTaskGroups: function() {
let groupedTasks = {};
for (let i = 0; i < this.tasks.length; i++) {
this._createGroupedTask(this.tasks[i], groupedTasks);
}
return groupedTasks;
},
_sortTaskGroups: function(groupedTasks) {
for (let groupArray in groupedTasks) {
if (groupedTasks.hasOwnProperty(groupArray)) {
groupedTasks[groupArray].sort(this.sortByPriority);
}
}
},
_createGroupSubMenu: function(name, tasks) {
let groupItem = new PopupMenu.PopupSubMenuMenuItem(name);
groupItem.setActive = Lang.bind(groupItem, function(active) {
let activeChanged = active != this.active;
if (activeChanged) {
this.active = active;
if (active) {
this.actor.add_style_class_name('selected');
}
else {
this.actor.remove_style_class_name('selected');
// Remove the CSS active state if the user press the button and
// while holding moves to another menu item, so we don't paint all items.
// The correct behaviour would be to set the new item with the CSS
// active state as well, but button-press-event is not trigered,
// so we should track it in our own, which would involve some work
// in the container
this.actor.remove_style_pseudo_class('active');
}
this.emit('active-changed', active);
}
});
for (let i = 0; i < tasks.length; i++) {
let item = this._createTodoItem(tasks[i]);
if (item !== null) {
groupItem.menu.addMenuItem(item);
}
}
return groupItem;
},
_createTasksMenu: function() {
if (this.groupBy == Shared.NO_GROUPING) {
this._addTasksToMain(this.tasks);
return;
}
let groupedTasks = this._createTaskGroups();
this._sortTaskGroups(groupedTasks);
for (let group in groupedTasks) {
if (groupedTasks.hasOwnProperty(group)) {
let groupItem = null;
if (group == '"__nogroup__"') {
if (this.groupUngrouped) {
groupItem = this._createGroupSubMenu(_('Ungrouped'), groupedTasks[group]);
}
else {
this._addTasksToMain(groupedTasks[group]);
continue;
}
}
else {
groupItem = this._createGroupSubMenu(group.replace(/^"/, '').replace(/"$/, ''),
groupedTasks[group]);
}
if (this.showNumberOfGroupElements) {
groupItem.label.text += ' (' + groupedTasks[group].length + ')';
}
this.menu.addMenuItem(groupItem);
}
}
},
_createTasksFromFile: function(lines) {
this.tasks.length = 0;
for (let i = 0; i < lines.length; i++) {
if (lines[i] !== '' && lines[i] != '\n') {
try {
let task = new JsTodo.TodoTxtItem(lines[i], this.enabledExtensions);
this.decorator.addLoggingToNamespace(task);
this.tasks.push(task);
}
catch (exception) {
this.logger.debug('Error while reading task: ' + exception.message);
}
}
}
},
_createGroupedTask: function(task, groupedTasks) {
let groups = task[this.groupedTasksParameter[this.groupBy]];
if (groups === null) {
groups = ['__nogroup__'];
}
for (let group in groups) {
if (groups.hasOwnProperty(group)) {
let groupName = '"' + groups[group] + '"';
if (typeof groupedTasks[groupName] == 'undefined') {
groupedTasks[groupName] = [task];
}
else {
groupedTasks[groupName].push(task);
}
}
}
},
_get_symlink_target_absolute: function(symlinkGFile) {
this.logger.debug('Getting absolute path for symlink ' + symlinkGFile.get_path());
let parentDir = symlinkGFile.get_parent();
if (parentDir === null) {
parentDir = Gio.file_new_for_path('/');
}
let symlinkTarget = symlinkGFile.query_info('standard::symlink-target', 0, null).get_symlink_target();
return parentDir.resolve_relative_path(symlinkTarget);
},
_linkChanged: function() {
if (this._monitorFile()) {
this._refresh();
}
},
_create_link_monitor_if_necessary: function(path) {
if (!Utils.isValid(path)) {
return null;
}
let gFile = Gio.file_new_for_path(path);
if (gFile.query_info('standard::is-symlink', 0, null).get_is_symlink()) {
if (this.linkMonitor !== null) {
this.linkMonitor.cancel();
}
this.linkMonitor = gFile.monitor(Gio.FileMonitorFlags.NONE, null);
this.linkMonitor.connect('changed', Lang.bind(this, this._linkChanged));
return this._get_symlink_target_absolute(gFile);
}
return null;
},
_get_g_file_for_path: function(path) {
let gFile = Gio.file_new_for_path(path);
if (!gFile.query_exists(null)) {
return gFile;
}
let hardLink = this._create_link_monitor_if_necessary(path);
if (hardLink !== null) {
return hardLink;
}
return gFile;
},
_launchPreferences: function() {
let runPrefs = 'gnome-shell-extension-prefs ' + Extension.metadata.uuid;
Main.Util.trySpawnCommandLine(runPrefs);
},
_getDefaultConfigPath: function() {
return GLib.build_pathv('/', [GLib.get_user_data_dir(), 'todo.txt']);
},
_fileExists: function(file) {
if (GLib.file_test(file, GLib.FileTest.EXISTS)) {
return true;
}
return false;
},
_createDefaultFileOrReuseExisting: function(path, fileName, setting) {
let file = GLib.build_filenamev([path, fileName]);
if (!this._fileExists(file)) {
GLib.file_set_contents(file, '');
this.settings.set(setting, file);
return;
}
let useExistingButton = new MultiButtonDialog.ButtonMapping(_('Use existing file'), null,
Lang.bind(this, function() {
this.logger.debug('Using existing file');
this.settings.set(setting, file);
}));
let overwriteExistingButton = new MultiButtonDialog.ButtonMapping(_('Create new file'), null,
Lang.bind(this, function() {
this.logger.debug('Creating new file');
GLib.file_set_contents(file, '');
this.settings.set(setting, file);
}));
let openSettingsButton = new MultiButtonDialog.ButtonMapping(_('Open settings'), Clutter.Return,
Lang.bind(this, function() {
this._launchPreferences();
}));
let cancelButton = new MultiButtonDialog.ButtonMapping(_('Cancel'), Clutter.Escape, null);
let buttons = [useExistingButton, overwriteExistingButton, openSettingsButton, cancelButton];
let dialog = new MultiButtonDialog.MultiButtonDialog(
_('%(file) exists already').replace('%(file)', file),
_('Please choose what you want to do'),
buttons
);
dialog.open();
},
_createDefaultFiles: function() {
let createPath = this._getDefaultConfigPath();
GLib.mkdir_with_parents(createPath, 493);
this._createDefaultFileOrReuseExisting(createPath, 'todo.txt', 'todotxt-location');
this._createDefaultFileOrReuseExisting(createPath, 'done.txt', 'donetxt-location');
},
_createNoFileMenu: function(file) {
this.topbar.update({
error: true
});
let errorItem = new PopupMenu.PopupMenuItem(
_('No valid %(filename) file specified').replace('%(filename)', file));
let chooseItem = new PopupMenu.PopupMenuItem('> ' + _('Select location in settings'));
chooseItem.connect('activate', Lang.bind(this, function() {
this._launchPreferences();
}));
let createItem = new PopupMenu.PopupMenuItem('> ' + _(
'Create todo.txt and done.txt file in %(path)').replace(
'%(path)', this._getDefaultConfigPath()));
createItem.connect('activate', Lang.bind(this, function() {
this._createDefaultFiles();
}));
this.menu.removeAll();
this.menu.clearSection('top');
this.menu.clearSection('bottom');
this.menu.addMenuItem(errorItem);
this.menu.addMenuItem(chooseItem);
this.menu.addMenuItem(createItem);
},
_monitored: function(monitor, file, other_file, event) {
if (this._checkForFile()) {
this._refresh();
}
},
_mountChanged: function() {
this.logger.debug('Mount changed, checking if file exists');
if (this._checkForFile()) {
this._refresh();
}
},
_monitorMounts: function() {
this.volumeMonitor = Gio.VolumeMonitor.get();
this.volumeMonitor.connect('mount-added', Lang.bind(this, this._mountChanged));
this.volumeMonitor.connect('mount-removed', Lang.bind(this, this._mountChanged));
},
_checkForFile: function() {
try {
let jsTextFile = new JsTextFile.JsTextFile(this.todofile, this.logger);
this.decorator.addLoggingToNamespace(jsTextFile);
this.logger.debug('File found: ' + this.todofile);
if (this.fileLoaded === false) {
this._create_link_monitor_if_necessary(this.todofile);
}
this.fileLoaded = true;
return true;
}
catch (exception) {
this.logger.info('File could not be monitored, showing \'no file\' menu');
this._createNoFileMenu('todo.txt');
this.fileLoaded = false;
return false;
}
},
_monitorFile: function() {
this._cancel_monitors();
let fileM = this._get_g_file_for_path(this.todofile);
this.logger.debug('Monitoring ' + fileM.get_path());
this.monitor = fileM.monitor(Gio.FileMonitorFlags.WATCH_MOUNTS | Gio.FileMonitorFlags.WATCH_MOVES,
null);
this.monitor.connect('changed', Lang.bind(this, this._monitored));
if (this._checkForFile()) {
this._refresh();
}
},
_enable: function() {
let menuManager = Main.panel._menus || Main.panel.menuManager;
menuManager.addMenu(this.menu);
this._monitorFile();
this._monitorMounts();
this._connectSettingsSignals();
},
_cancel_monitors: function() {
if (this.monitor !== null) {
if (!this.monitor.cancel()) {
this.debug.error('Could not cancel file monitor');
}
this.monitor = null;
}
if (this.linkMonitor !== null) {
if (!this.linkMonitor.cancel()) {
this.debug.error('Could not cancel link monitor');
}
this.linkMonitor = null;
}
},
_disable: function() {
let menuManager = Main.panel._menus || Main.panel.menuManager;
menuManager.removeMenu(this.menu);
this._cancel_monitors();
global.display.remove_keybinding(openKey);
this.settings.unregisterCallbacks();
},
onTodoFileChanged: function() {
this._loadSettings();
this._cancel_monitors();
if (this._monitorFile()) {
this._refresh();
return;
}
},
onParamChanged: function(self, key) {
this.logger.debug(key + ' has changed to ' + this.settings.get(key));
if (key == 'auto-archive') {
this.autoarchive = this.settings.get('auto-archive');
return;
}
if (key == 'donetxt-location') {
this.donefile = this.settings.get('donetxt-location');
this._refresh();
return;
}
if (key == 'debug-level') {
this.debugLevel = this.settings.get('debug-level');
this.logger.setLevel(this.debugLevel);
return;
}
if (key == 'add-creation-date') {
this.addCreationDate = this.settings.get('add-creation-date');
return;
}
if (key == 'priority-on-done') {
this.priorityOnDone = this.settings.get('priority-on-done');
return;
}
if (key == 'keep-open-after-new') {
this.keepOpenAfterNew = this.settings.get('keep-open-after-new');
return;
}
this._loadSettings();
this._refresh();
},
_addKeyBinding: function(key, keyFunction) {
if (Main.wm.addKeybinding) {
let mode = Shell.ActionMode;
if (typeof mode == 'undefined') {
mode = Shell.KeyBindingMode;
}
Main.wm.addKeybinding(key, this.settings.getGioSettings(), Meta.KeyBindingFlags.NONE,
mode.ALL, keyFunction);
return;
}
global.display.add_keybinding(key, this.settings.getGioSettings(), Meta.KeyBindingFlags.NONE,
keyFunction);
},
_removeKeyBinding: function(key) {
if (Main.wm.removeKeybinding) {
Main.wm.removeKeybinding(key);
}
else {
global.display.remove_keybinding(key);
}
},
_installShortcuts: function() {
this._addKeyBinding(openKey, Lang.bind(this, function() {
this.menu.open();
}));
},
onShortcutChanged: function() {
this._removeKeyBinding(openKey);
this._installShortcuts();
this._loadSettings();
},
removeTask: function(task) {
let index = this.tasks.indexOf(task);
if (index == -1) {
this.logger.debug('Task not found');
return false;
}
this.tasks.splice(index, 1);
return this.saveTasksToFile();
},
addTask: function(task) {
if (this.addCreationDate) {
task.date = new Date();
}
if (this.insertTaskAtTop === true) {
this.tasks.unshift(task);
}
else {
this.tasks.push(task);
}
return this.saveTasksToFile();
},
modifyTask: function(oldTask, newTask, save) {
let index = this.tasks.indexOf(oldTask);
if (index == -1) {
this.logger.debug('Task not found');
return false;
}
this.tasks[index] = newTask;
if (save) {
return this.saveTasksToFile();
}
return true;
},
_modifyTaskPriorityOnComplete: function(task) {
if (this.priorityOnDone == Shared.TASK_DONE_PRIORITY_REMOVE) {
task.priority = null;
return;
}
if (this.priorityOnDone == Shared.TASK_DONE_PRIORITY_KEEP_PRI) {
task.text += ' pri:' + task.priority;
task.priority = null;
return;
}
},
completeTask: function(task) {
let doneTask = new JsTodo.TodoTxtItem(task.toString(), this.enabledExtensions);
this.decorator.addLoggingToNamespace(doneTask);
doneTask.complete = true;
doneTask.completed = new Date();
if (doneTask.priority !== null) {
this._modifyTaskPriorityOnComplete(doneTask);
}
// Modify tasks list, but don't save yet
if (!this.modifyTask(task, doneTask, false)) {
return false;
}
// If autoarchive is on, archive task and save both files
if (this.autoarchive) {
return this.archiveTask(doneTask);
}
// If autoarchive is off, only save todo.txt file
return this.saveTasksToFile();
},
archiveTask: function(task) {
if (!task.complete) {
this.logger.debug('archiveTask: trying to archive task that is not done');
return false;
}
try {
let jsTextFile = new JsTextFile.JsTextFile(this.donefile, this.logger);
this.decorator.addLoggingToNamespace(jsTextFile);
if (!jsTextFile.addLine(task.toString(), this.insertTaskAtTop)) {
this.logger.debug('Could not add task to done file');
}
jsTextFile.saveFile(true);
return this.removeTask(task);
}
catch (exception) {
let title = _('Error writing file');
let message = null;
if (exception.type == Errors.TodoTxtErrorTypes.FILE_WRITE_PERMISSION_ERROR ||
exception.type == Errors.TodoTxtErrorTypes.FILE_WRITE_ERROR) {
message = new Message(title, exception.message);
}
else if (exception instanceof Errors.IoError) {
this._createNoFileMenu('done.txt');
}
else {
message = new Message(title,
_('Unknown error during file write: %(error)').replace('%(error)', exception.toString())
);
}
message.open();
}
return false;
},
_traverseChars: function(char, prev) {
let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
if (char == chars.charAt(0) && prev) {
return chars.charAt(chars.length - 1);
}
if (char == chars.charAt(chars.length - 1) && !prev) {
return chars.charAt(0);
}
if ((typeof char == 'undefined' || char === null) && prev) {
this.logger.debug('undefined char, returning ' + chars.charAt(0));
return chars.charAt(0);
}
if ((typeof char == 'undefined' || char === null) && !prev) {
this.logger.debug('undefined char, returning ' + chars.charAt(chars.length - 1));
return chars.charAt(chars.length - 1);
}
return chars.charAt(chars.indexOf(char) + ((prev === true) ? -1 : 1));
},
modifyTaskPriority: function(task, higher) {
let newTask = new JsTodo.TodoTxtItem(task.toString(), this.enabledExtensions);
this.decorator.addLoggingToNamespace(newTask);
this.logger.debug('Modify' + task.toString() + ', higher:' + higher);
newTask.priority = this._traverseChars(task.priority, higher);
return this.modifyTask(task, newTask, true);
},
saveTasksToFile: function() {
let jsTextFile = new JsTextFile.JsTextFile(this.todofile, this.logger);
this.decorator.addLoggingToNamespace(jsTextFile);
let textArray = [];
for (let i = 0; i < this.tasks.length; i++) {
textArray[i] = this.tasks[i].toString();
}
jsTextFile.setLines(textArray);
try {
return jsTextFile.saveFile(true);
}
catch (exception) {
let title = _('Error writing file');
let message = null;
if (exception.type == Errors.TodoTxtErrorTypes.FILE_WRITE_PERMISSION_ERROR ||
exception.type == Errors.TodoTxtErrorTypes.FILE_WRITE_ERROR) {
message = new Message(title, exception.message);
}
else {
message = new Message(title, _('Unknown error during file write: %(error)').replace(
'%(error)', exception.toString()));
}
message.open();
}
return false;
},
sortByPriority: function(a, b) {
if (a.priority === null) {
if (b.priority === null) {
return 0;
}
// Convention: 'null' has smaller priority then everything else
return 1;
}
if (b.priority === null) {
// Case a==null, b==null already covered
return -1;
}
return (a.priority.charCodeAt(0) - b.priority.charCodeAt(0));
}
});
function enable() {
let logger = Utils.getDefaultLogger();
let path = Utils.getFirstValidChild(Extension, ['path', 'metadata.path']);
let theme = imports.gi.Gtk.IconTheme.get_default();
theme.append_search_path(path + '/icons');
Utils.initTranslations(Extension);
todoTxt = new TodoTxtManager(logger);
let decorator = new Decorator();
decorator.setLogger(logger.flow);
decorator.addLoggingToNamespace(todoTxt);
todoTxt._enable();
Main.panel.addToStatusArea('todoTxt', todoTxt);
}
function disable() {
todoTxt._disable();
todoTxt.destroy();
todoTxt = null;
}
/* vi: set expandtab tabstop=4 shiftwidth=4: */