rework of Files.Jsons

In the same way as Files.Images.
This commit is contained in:
abakkk 2020-09-13 23:50:09 +02:00
parent e53e69efcf
commit 60091a94b6
4 changed files with 190 additions and 106 deletions

83
area.js
View File

@ -1129,14 +1129,7 @@ var DrawingArea = new Lang.Class({
} }
content += "\n</svg>"; content += "\n</svg>";
let filename = `${Me.metadata['svg-file-name']} ${Files.getDateString()}.svg`; if (Files.saveSvg(content)) {
let dir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES);
let path = GLib.build_filenamev([dir, filename]);
if (GLib.file_test(path, GLib.FileTest.EXISTS))
return false;
let success = GLib.file_set_contents(path, content);
if (success) {
// pass the parent (bgContainer) to Flashspot because coords of this are relative // pass the parent (bgContainer) to Flashspot because coords of this are relative
let flashspot = new Screenshot.Flashspot(this.get_parent()); let flashspot = new Screenshot.Flashspot(this.get_parent());
flashspot.fire(); flashspot.fire();
@ -1149,7 +1142,7 @@ var DrawingArea = new Lang.Class({
} }
}, },
_saveAsJson: function(name, notify, callback) { _saveAsJson: function(json, notify, callback) {
// stop drawing or writing // stop drawing or writing
if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting) { if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting) {
this._stopWriting(); this._stopWriting();
@ -1157,46 +1150,31 @@ var DrawingArea = new Lang.Class({
this._stopDrawing(); this._stopDrawing();
} }
let json = new Files.Json({ name });
let oldContents;
if (name == Me.metadata['persistent-file-name']) {
let oldContents = json.contents;
// do not create a file to write just an empty array
if (!oldContents && this.elements.length == 0)
return;
}
// do not use "content = JSON.stringify(this.elements, null, 2);", neither "content = JSON.stringify(this.elements);" // do not use "content = JSON.stringify(this.elements, null, 2);", neither "content = JSON.stringify(this.elements);"
// do compromise between disk usage and human readability // do compromise between disk usage and human readability
let contents = `[\n ` + new Array(...this.elements.map(element => JSON.stringify(element))).join(`,\n\n `) + `\n]`; let contents = this.elements.length ? `[\n ` + new Array(...this.elements.map(element => JSON.stringify(element))).join(`,\n\n `) + `\n]` : '[]';
if (name == Me.metadata['persistent-file-name'] && contents == oldContents)
return;
GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
json.contents = contents; json.contents = contents;
if (notify) if (notify)
this.emit('show-osd', Files.Icons.SAVE, name, "", -1, false); this.emit('show-osd', Files.Icons.SAVE, json.name, "", -1, false);
if (name != Me.metadata['persistent-file-name']) { if (!json.isPersistent)
this.jsonName = name; this.currentJson = json;
this.lastJsonContents = contents;
}
if (callback) if (callback)
callback(); callback();
}); });
}, },
saveAsJsonWithName: function(name, callback) { saveAsJsonWithName: function(name, callback) {
this._saveAsJson(name, false, callback); this._saveAsJson(Files.Jsons.getNamed(name), false, callback);
}, },
saveAsJson: function() { saveAsJson: function() {
this._saveAsJson(Files.getDateString(), true); this._saveAsJson(Files.Jsons.getDated(), true);
}, },
savePersistent: function() { savePersistent: function() {
this._saveAsJson(Me.metadata['persistent-file-name']); this._saveAsJson(Files.Jsons.getPersistent());
}, },
syncPersistent: function() { syncPersistent: function() {
@ -1208,7 +1186,7 @@ var DrawingArea = new Lang.Class({
}, },
_loadJson: function(name, notify) { _loadJson: function(json, notify) {
// stop drawing or writing // stop drawing or writing
if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting) { if (this.currentElement && this.currentElement.shape == Shapes.TEXT && this.isWriting) {
this._stopWriting(); this._stopWriting();
@ -1218,56 +1196,45 @@ var DrawingArea = new Lang.Class({
this.elements = []; this.elements = [];
this.currentElement = null; this.currentElement = null;
let contents = (new Files.Json({ name })).contents; if (!json.contents)
if (!contents)
return; return;
this.elements.push(...JSON.parse(contents).map(object => { this.elements.push(...JSON.parse(json.contents).map(object => {
if (object.image) if (object.image)
object.image = new Files.Image(object.image); object.image = new Files.Image(object.image);
return new Elements.DrawingElement(object); return new Elements.DrawingElement(object);
})); }));
if (notify) if (notify)
this.emit('show-osd', Files.Icons.OPEN, name, "", -1, false); this.emit('show-osd', Files.Icons.OPEN, json.name, "", -1, false);
if (name != Me.metadata['persistent-file-name']) { if (!json.isPersistent)
this.jsonName = name; this.currentJson = json;
this.lastJsonContents = contents;
}
}, },
_loadPersistent: function() { _loadPersistent: function() {
this._loadJson(Me.metadata['persistent-file-name']); this._loadJson(Files.Jsons.getPersistent());
}, },
loadJson: function(name, notify) { loadJson: function(json, notify) {
this._loadJson(name, notify); this._loadJson(json, notify);
this._redisplay(); this._redisplay();
}, },
loadPreviousJson: function() { loadPreviousJson: function() {
let names = Files.getJsons().map(json => json.name); let json = Files.Jsons.getPrevious(this.currentJson || null);
if (json)
if (!names.length) this.loadJson(json, true);
return;
let previousName = names[this.jsonName && names.indexOf(this.jsonName) != names.length - 1 ? names.indexOf(this.jsonName) + 1 : 0];
this.loadJson(previousName, true);
}, },
loadNextJson: function() { loadNextJson: function() {
let names = Files.getJsons().map(json => json.name); let json = Files.Jsons.getNext(this.currentJson || null);
if (json)
if (!names.length) this.loadJson(json, true);
return;
let nextName = names[this.jsonName && names.indexOf(this.jsonName) > 0 ? names.indexOf(this.jsonName) - 1 : names.length - 1];
this.loadJson(nextName, true);
}, },
get drawingContentsHasChanged() { get drawingContentsHasChanged() {
let contents = `[\n ` + new Array(...this.elements.map(element => JSON.stringify(element))).join(`,\n\n `) + `\n]`; let contents = `[\n ` + new Array(...this.elements.map(element => JSON.stringify(element))).join(`,\n\n `) + `\n]`;
return contents != this.lastJsonContents; return contents != (this.currentJson && this.currentJson.contents);
} }
}); });

View File

@ -524,6 +524,8 @@ const AreaManager = new Lang.Class({
Main.wm.removeKeybinding('toggle-modal'); Main.wm.removeKeybinding('toggle-modal');
Main.wm.removeKeybinding('erase-drawings'); Main.wm.removeKeybinding('erase-drawings');
this.removeAreas(); this.removeAreas();
Files.Images.disable();
Files.Jsons.disable();
if (this.indicator) if (this.indicator)
this.indicator.disable(); this.indicator.disable();
} }

183
files.js
View File

@ -1,5 +1,5 @@
/* jslint esversion: 6 */ /* jslint esversion: 6 */
/* exported Icons, Image, Images, Json, getJsons, getDateString */ /* exported Icons, Image, Images, Json, Jsons, getDateString, saveSvg */
/* /*
* Copyright 2019 Abakkk * Copyright 2019 Abakkk
@ -205,6 +205,12 @@ var Images = {
_clipboardImages: [], _clipboardImages: [],
_upToDate: false, _upToDate: false,
disable: function() {
this._images = [];
this._clipboardImages = [];
this._upToDate = false;
},
_clipboardImagesContains: function(file) { _clipboardImagesContains: function(file) {
return this._clipboardImages.some(image => image.file.equal(file)); return this._clipboardImages.some(image => image.file.equal(file));
}, },
@ -265,7 +271,7 @@ var Images = {
let file = this.enumerator.get_child(info); let file = this.enumerator.get_child(info);
if (info.get_content_type().indexOf('image') == 0 && !clipboardImagesContains(file)) { if (info.get_content_type().indexOf('image') == 0 && !clipboardImagesContains(file)) {
let image = oldImages.find(image => image.file.equal(file)) || new ImageWithGicon({ file, info }); let image = oldImages.find(oldImage => oldImage.file.equal(file)) || new ImageWithGicon({ file, info });
newImages.push(image); newImages.push(image);
return { value: image, done: false }; return { value: image, done: false };
} else { } else {
@ -287,7 +293,7 @@ var Images = {
getPrevious: function(currentImage) { getPrevious: function(currentImage) {
let images = this.getSorted(); let images = this.getSorted();
let index = currentImage ? images.findIndex(image => image.file.equal(currentImage.file)) : 0; let index = currentImage ? images.findIndex(image => image.file.equal(currentImage.file)) : -1;
return images[index <= 0 ? images.length - 1 : index - 1] || null; return images[index <= 0 ? images.length - 1 : index - 1] || null;
}, },
@ -333,6 +339,10 @@ var Json = new Lang.Class({
this[key] = params[key]; this[key] = params[key];
}, },
get isPersistent() {
return this.name == Me.metadata['persistent-file-name'];
},
toString: function() { toString: function() {
return this.displayName || this.name; return this.displayName || this.name;
}, },
@ -342,10 +352,10 @@ var Json = new Lang.Class({
}, },
get file() { get file() {
if (!this._file && this.name) if (!this._file)
this._file = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir'], `${this.name}.json`])); this._file = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir'], `${this.name}.json`]));
return this._file || null; return this._file;
}, },
set file(file) { set file(file) {
@ -353,62 +363,167 @@ var Json = new Lang.Class({
}, },
get contents() { get contents() {
let success_, contents; if (this._contents === undefined) {
try { try {
[success_, contents] = this.file.load_contents(null); [, this._contents] = this.file.load_contents(null);
if (contents instanceof Uint8Array) if (this._contents instanceof Uint8Array)
contents = ByteArray.toString(contents); this._contents = ByteArray.toString(this._contents);
} catch(e) { } catch(e) {
return null; this._contents = null;
} }
return contents; }
return this._contents;
}, },
set contents(contents) { set contents(contents) {
if (this.isPersistent && (this.contents == contents || !this.contents && contents == '[]'))
return;
try { try {
this.file.replace_contents(contents, null, false, Gio.FileCreateFlags.NONE, null); this.file.replace_contents(contents, null, false, Gio.FileCreateFlags.NONE, null);
} catch(e) { } catch(e) {
this.file.get_parent().make_directory_with_parents(null); this.file.get_parent().make_directory_with_parents(null);
this.file.replace_contents(contents, null, false, Gio.FileCreateFlags.NONE, null); this.file.replace_contents(contents, null, false, Gio.FileCreateFlags.NONE, null);
} }
this._contents = contents;
} }
}); });
var getJsons = function() { var Jsons = {
_jsons: [],
_upToDate: false,
disable: function() {
if (this._monitor) {
this._monitor.disconnect(this._monitorHandler);
this._monitor.cancel();
}
delete this._monitor;
delete this._persistent;
this._jsons = [];
this._upToDate = false;
},
_updateMonitor: function() {
if (this._monitor)
return;
let directory = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir']])); let directory = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir']]));
this._monitor = directory.monitor(Gio.FileMonitorFlags.NONE, null);
this._monitorHandler = this._monitor.connect('changed', (monitor, file) => {
if (file.get_basename() != `${Me.metadata['persistent-file-name']}.json` && file.get_basename().indexOf('.goutputstream'))
this.reset();
});
},
let enumerator; [Symbol.iterator]: function() {
if (this._upToDate)
return this._jsons[Symbol.iterator]();
this._updateMonitor();
this._upToDate = true;
let newJsons = this._jsons = [];
return {
get enumerator() {
if (this._enumerator === undefined) {
try { try {
enumerator = directory.enumerate_children('standard::name,standard::display-name,standard::content-type,time::modified', Gio.FileQueryInfoFlags.NONE, null); let directory = Gio.File.new_for_path(GLib.build_filenamev([GLib.get_user_data_dir(), Me.metadata['data-dir']]));
this._enumerator = directory.enumerate_children('standard::name,standard::display-name,standard::content-type,time::modified', Gio.FileQueryInfoFlags.NONE, null);
} catch(e) { } catch(e) {
return []; this._enumerator = null;
}
} }
let jsons = []; return this._enumerator;
let fileInfo = enumerator.next_file(null); },
while (fileInfo) {
if (fileInfo.get_content_type().indexOf('json') != -1 && fileInfo.get_name() != `${Me.metadata['persistent-file-name']}.json`) {
let file = enumerator.get_child(fileInfo);
jsons.push(new Json({
file,
name: fileInfo.get_name().slice(0, -5),
displayName: fileInfo.get_display_name().slice(0, -5),
// fileInfo.get_modification_date_time: Gio 2.62+
modificationUnixTime: fileInfo.get_attribute_uint64('time::modified')
}));
}
fileInfo = enumerator.next_file(null);
}
enumerator.close(null);
jsons.sort((a, b) => { next: function() {
return b.modificationUnixTime - a.modificationUnixTime; if (!this.enumerator || this.enumerator.is_closed())
return { done: true };
let info = this.enumerator.next_file(null);
if (!info) {
this.enumerator.close(null);
return this.next();
}
let file = this.enumerator.get_child(info);
if (info.get_content_type().indexOf('json') != -1 && info.get_name() != `${Me.metadata['persistent-file-name']}.json`) {
let json = new Json({
file, name: info.get_name().slice(0, -5),
displayName: info.get_display_name().slice(0, -5),
// info.get_modification_date_time: Gio 2.62+
modificationUnixTime: info.get_attribute_uint64('time::modified')
}); });
return jsons; newJsons.push(json);
return { value: json, done: false };
} else {
return this.next();
}
}
};
},
getSorted: function() {
return [...this].sort((a, b) => b.modificationUnixTime - a.modificationUnixTime);
},
getNext: function(currentJson) {
let jsons = this.getSorted();
let index = currentJson ? jsons.findIndex(json => json.name == currentJson.name) : -1;
return jsons[index == jsons.length - 1 ? 0 : index + 1] || null;
},
getPrevious: function(currentJson) {
let jsons = this.getSorted();
let index = currentJson ? jsons.findIndex(json => json.name == currentJson.name) : -1;
return jsons[index <= 0 ? jsons.length - 1 : index - 1] || null;
},
getPersistent: function() {
if (!this._persistent)
this._persistent = new Json({ name: Me.metadata['persistent-file-name'] });
return this._persistent;
},
getDated: function() {
return new Json({ name: getDateString() });
},
getNamed: function(name) {
return [...this].find(json => json.name == name) || new Json({ name });
},
reset: function() {
this._upToDate = false;
}
}; };
var getDateString = function() { var getDateString = function() {
let date = GLib.DateTime.new_now_local(); let date = GLib.DateTime.new_now_local();
return `${date.format("%F")} ${date.format("%X")}`; return `${date.format("%F")} ${date.format("%X")}`;
}; };
var saveSvg = function(content) {
let filename = `${Me.metadata['svg-file-name']} ${getDateString()}.svg`;
let dir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES);
let path = GLib.build_filenamev([dir, filename]);
let file = Gio.File.new_for_path(path);
if (file.query_exists(null))
return false;
try {
return file.replace_contents(content, null, false, Gio.FileCreateFlags.NONE, null);
} catch(e) {
return false;
}
};

12
menu.js
View File

@ -562,10 +562,10 @@ var DrawingMenu = new Lang.Class({
}, },
_updateDrawingNameMenuItem: function() { _updateDrawingNameMenuItem: function() {
getActor(this.drawingNameMenuItem).visible = this.area.jsonName ? true : false; getActor(this.drawingNameMenuItem).visible = this.area.currentJson ? true : false;
if (this.area.jsonName) { if (this.area.currentJson) {
let prefix = this.area.drawingContentsHasChanged ? "* " : ""; let prefix = this.area.drawingContentsHasChanged ? "* " : "";
this.drawingNameMenuItem.label.set_text(`<i>${prefix}${this.area.jsonName}</i>`); this.drawingNameMenuItem.label.set_text(`<i>${prefix}${this.area.currentJson.name}</i>`);
this.drawingNameMenuItem.label.get_clutter_text().set_use_markup(true); this.drawingNameMenuItem.label.get_clutter_text().set_use_markup(true);
} }
}, },
@ -574,7 +574,7 @@ var DrawingMenu = new Lang.Class({
let item = new PopupMenu.PopupSubMenuMenuItem(_("Open drawing"), true); let item = new PopupMenu.PopupSubMenuMenuItem(_("Open drawing"), true);
this.openDrawingSubMenuItem = item; this.openDrawingSubMenuItem = item;
this.openDrawingSubMenu = item.menu; this.openDrawingSubMenu = item.menu;
item.setSensitive(Boolean(Files.getJsons().length)); item.setSensitive(Boolean(Files.Jsons.getSorted().length));
item.icon.set_gicon(icon); item.icon.set_gicon(icon);
item.menu.itemActivated = item.menu.close; item.menu.itemActivated = item.menu.close;
@ -591,10 +591,10 @@ var DrawingMenu = new Lang.Class({
_populateOpenDrawingSubMenu: function() { _populateOpenDrawingSubMenu: function() {
this.openDrawingSubMenu.removeAll(); this.openDrawingSubMenu.removeAll();
let jsons = Files.getJsons(); let jsons = Files.Jsons.getSorted();
jsons.forEach(json => { jsons.forEach(json => {
let subItem = this.openDrawingSubMenu.addAction(`<i>${String(json)}</i>`, () => { let subItem = this.openDrawingSubMenu.addAction(`<i>${String(json)}</i>`, () => {
this.area.loadJson(json.name); this.area.loadJson(json);
this._updateDrawingNameMenuItem(); this._updateDrawingNameMenuItem();
this._updateSaveDrawingSubMenuItemSensitivity(); this._updateSaveDrawingSubMenuItemSensitivity();
}); });