# Copyright 2017-2018 Xuan Sang LE # AnTOS Web desktop is is licensed under the GNU General Public # License v3.0, see the LICENCE file for more information # 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 https://www.gnu.org/licenses/. class NotePad extends this.OS.GUI.BaseApplication constructor: ( args ) -> super "NotePad", args main: () -> me = @ @scheme.set "apptitle", "NotePad" @sidebar = @find "sidebar" @location = @find "location" @fileview = @find "fileview" div = @find "datarea" ace.require "ace/ext/language_tools" @currfile = if @args and @args.length > 0 then @args[0].asFileHandler() else "Untitled".asFileHandler() @.editor = ace.edit div @.editor.setOptions { enableBasicAutocompletion: true, enableSnippets: true, enableLiveAutocompletion: true, fontSize: "9pt" } @.editor.completers.push { getCompletions: ( editor, session, pos, prefix, callback ) -> } @.editor.getSession().setUseWrapMode true @fileview.contextmenuHandler = (e, m) -> m.set "items", me.contextMenu() m.set "onmenuselect", (evt) -> me.contextAction evt m.show e @mlist = @find "modelist" @modes = ace.require "ace/ext/modelist" ldata = [] f = (m, i) -> ldata.push { text: m.name, mode: m.mode, selected: if m.mode is 'ace/mode/text' then true else false } m.idx = i f(m, i) for m, i in @modes.modes @mlist.set "items", ldata @mlist.set "onlistselect", (e) -> me.editor.session.setMode e.data.mode themelist = @find "themelist" themes = ace.require "ace/ext/themelist" ldata = [] ldata.push { text: m.caption, mode: m.theme, selected: if m.theme is "ace/theme/monokai" then true else false } for k, m of themes.themesByName themelist.set "onlistselect", (e) -> me.editor.setTheme e.data.mode themelist.set "items", ldata stat = @find "editorstat" #status stup = (e) -> c = me.editor.session.selection.getCursor() l = me.editor.session.getLength() stat.set "text", __("Row {0}, col {1}, lines: {2}", c.row, c.column, l) stup(0) @.editor.getSession().selection.on "changeCursor", (e) -> stup(e) @editormux = false @editor.on "input", () -> if me.editormux me.editormux = false return false if not me.currfile.dirty me.currfile.dirty = true me.currfile.text += "*" me.tabarea.update() @on "resize", () -> me.editor.resize() @on "focus", () -> me.editor.focus() @fileview.set "chdir", (d) -> me.chdir d @fileview.set "fetch", (e, f) -> return unless e.child return if e.child.filename is "[..]" e.child.path.asFileHandler().read (d) -> return me.error __("Resource not found {0}", e.child.path) if d.error f d.result @fileview.set "onfileopen", (e) -> return if e.type is "dir" me.open e.path.asFileHandler() @subscribe "VFS", (d) -> p = (me.fileview.get "path").asFileHandler() me.chdir p.path if d.data.file.hash() is p.hash() or d.data.file.parent().hash() is p.hash() @location.set "onlistselect", (e) -> me.chdir e.data.path @location.set "items", ( i for i in @systemsetting.VFS.mountpoints when i.type isnt "app" ) @location.set "selected", 0 unless @location.get "selected" @tabarea = @find "tabarea" @tabarea.set "ontabselect", (e) -> me.selecteTab e.idx @tabarea.set "onitemclose", (e) -> it = e.item.item return false unless it return me.closeTab it unless it.dirty me.openDialog "YesNoDialog", (d) -> return me.closeTab it if d me.editor.focus() , __("Close tab"), { text: __("Close without saving ?") } return false #@tabarea.set "closable", true @bindKey "ALT-N", () -> me.actionFile "#{me.name}-New" @bindKey "ALT-O", () -> me.actionFile "#{me.name}-Open" @bindKey "CTRL-S", () -> me.actionFile "#{me.name}-Save" @bindKey "ALT-W", () -> me.actionFile "#{me.name}-Saveas" @open @currfile open: (file) -> #find table i = @findTabByFile file @fileview.set "preventUpdate", true return @tabarea.set "selected", i if i isnt -1 return @newtab file if file.path.toString() is "Untitled" me = @ file.read (d) -> file.cache = d or "" me.newtab file contextMenu: () -> [ { text: __("New file"), dataid: "#{@name}-mkf" }, { text: __("New folder"), dataid: "#{@name}-mkd" }, { text: __("Delete"), dataid: "#{@name}-rm" } { text: __("Refresh"), dataid: "#{@name}-refresh" } ] contextAction: (e) -> me = @ file = @fileview.get "selectedFile" dir = if file then file.path.asFileHandler() else (@fileview.get "path").asFileHandler() console.log dir dir = dir.parent().asFileHandler() if file and file.type isnt "dir" switch e.item.data.dataid when "#{@name}-mkd" @openDialog "PromptDialog", (d) -> dir.mk d, (r) -> me.error __("Fail to create {0}: {1}", d, r.error) if r.error , "__(New folder)" when "#{@name}-mkf" @openDialog "PromptDialog", (d) -> fp = "#{dir.path}/#{d}".asFileHandler() fp.write "", (r) -> me.error __("Fail to create {0}: {1}", d, r.error) if r.error , "__(New file)" when "#{@name}-rm" return unless file @openDialog "YesNoDialog", (d) -> return unless d file.path.asFileHandler() .remove (r) -> me.error __("Fail to delete {0}: {1}", file.filename, r.error) if r.error , "__(Delete)" , { iconclass: "fa fa-question-circle", text: __("Do you really want to delete: {0}?", file.filename) } when "#{@name}-refresh" @.chdir ( @fileview.get "path" ) save: (file) -> me = @ file.write "text/plain", (d) -> return me.error __("Error saving file {0}", file.basename) if d.error file.dirty = false file.text = file.basename me.tabarea.update() findTabByFile: (file) -> lst = @tabarea.get "items" its = ( i for d, i in lst when d.hash() is file.hash() ) return -1 if its.length is 0 return its[0] closeTab: (it) -> @tabarea.remove it, false cnt = @tabarea.get "count" if cnt is 0 @open "Untitled".asFileHandler() return false @tabarea.set "selected", cnt - 1 return false newtab: (file) -> file.text = if file.basename then file.basename else file.path file.cache = "" unless file.cache file.um = new ace.UndoManager() @currfile.selected = false file.selected = true #console.log cnt @tabarea.push file, true #@currfile = @file #TODO: fix problem : @tabarea.set "selected", cnt selecteTab: (i) -> #return if i is @tabarea.get "selidx" file = (@tabarea.get "items")[i] return unless file @scheme.set "apptitle", file.text.toString() #return if file is @currfile if @currfile isnt file @currfile.cache = @editor.getValue() @currfile.cursor = @editor.selection.getCursor() @currfile = file m = "ace/mode/text" m = (@modes.getModeForPath file.path) if file.path.toString() isnt "Untitled" @mlist.set "selected", m.idx @editormux = true @editor.setValue file.cache, -1 @editor.session.setMode m.mode @editor.session.setUndoManager file.um if file.cursor @editor.renderer.scrollCursorIntoView { row: file.cursor.row, column: file.cursor.column }, 0.5 @editor.selection.moveTo file.cursor.row, file.cursor.column @editor.focus() chdir: (pth) -> #console.log "called", @_api.throwe("FCK") return unless pth me = @ dir = pth.asFileHandler() dir.read (d) -> if(d.error) return me.error __("Resource not found {0}", p) if not dir.isRoot() p = dir.parent().asFileHandler() p.filename = "[..]" p.type = "dir" #p.size = 0 d.result.unshift p ($ me.navinput).val dir.path me.fileview.set "path", pth me.fileview.set "data", d.result menu: () -> me = @ menu = [{ text: "__(File)", child: [ { text: "__(New)", dataid: "#{@name}-New", shortcut: "A-N" }, { text: "__(Open)", dataid: "#{@name}-Open", shortcut: "A-O" }, { text: "__(Save)", dataid: "#{@name}-Save", shortcut: "C-S" }, { text: "__(Save as)", dataid: "#{@name}-Saveas", shortcut: "A-W" } ], onmenuselect: (e) -> me.actionFile e.item.data.dataid }] menu actionFile: (e) -> me = @ saveas = () -> me.openDialog "FileDiaLog", (d, n) -> file = "#{d}/#{n}".asFileHandler() file.cache = me.currfile.cache file.dirty = me.currfile.dirty file.um = me.currfile.um file.cursor = me.currfile.cursor file.selected = me.currfile.selected file.text = me.currfile.text me.tabarea.replaceItem me.currfile, file, false me.currfile = file me.save me.currfile , "__(Save as)", { file: me.currfile } switch e when "#{@name}-Open" @openDialog "FileDiaLog", ( d, f ) -> me.open "#{d}/#{f}".asFileHandler() , "__(Open file)" when "#{@name}-Save" @currfile.cache = @editor.getValue() return @save @currfile if @currfile.basename saveas() when "#{@name}-Saveas" @currfile.cache = @editor.getValue() saveas() when "#{@name}-New" @open "Untitled".asFileHandler() cleanup: (evt) -> dirties = ( v for v in @tabarea.get "items" when v.dirty ) return if dirties.length is 0 me = @ evt.preventDefault() @.openDialog "YesNoDialog", (d) -> if d v.dirty = false for v in dirties me.quit() , "__(Quit)", { text: __("Ignore all {0} unsaved files ?", dirties.length) } NotePad.singleton = false NotePad.dependencies = [ "ace/ace", "ace/ext-language_tools", "ace/ext-modelist", "ace/ext-themelist" ] this.OS.register "NotePad", NotePad