FileView.hx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. package hide.view;
  2. class FileView extends hide.ui.View<{ path : String }> {
  3. public var extension(get,never) : String;
  4. public var modified(default, set) : Bool = false;
  5. var skipNextChange : Bool;
  6. var lastSaveTag : Int;
  7. var currentSign : String;
  8. public function new(state) {
  9. super(state);
  10. if( state.path != null )
  11. watch(state.path, function() {
  12. if( skipNextChange ) {
  13. skipNextChange = false;
  14. return;
  15. }
  16. onFileChanged(!sys.FileSystem.exists(ide.getPath(state.path)));
  17. }, { checkDelete : true, keepOnRebuild : true });
  18. }
  19. override function onRebuild() {
  20. var path = getPath();
  21. if( path != null ) {
  22. saveDisplayKey = Type.getClassName(Type.getClass(this)) + ":" + path.split("\\").join("/");
  23. if( !sys.FileSystem.exists(path) ) {
  24. element.html('${state.path} no longer exists');
  25. return;
  26. }
  27. }
  28. super.onRebuild();
  29. }
  30. function makeSign() {
  31. var content = sys.io.File.getContent(getPath());
  32. return haxe.crypto.Md5.encode(content);
  33. }
  34. function onFileChanged( wasDeleted : Bool, rebuildView = true ) {
  35. if( !wasDeleted && currentSign != null ) {
  36. // double check if content has changed
  37. if( makeSign() == currentSign )
  38. return;
  39. }
  40. if( wasDeleted ) {
  41. if( modified ) return;
  42. element.html('${state.path} no longer exists');
  43. return;
  44. }
  45. if( modified && !ide.confirm('${state.path} has been modified, reload and ignore local changes?') )
  46. return;
  47. modified = false;
  48. lastSaveTag = 0;
  49. undo.clear(); // prevent any undo that would reset past reload
  50. if( rebuildView )
  51. rebuild();
  52. }
  53. function get_extension() {
  54. if( state.path == null )
  55. return "";
  56. var file = state.path.split("/").pop();
  57. return file.indexOf(".") < 0 ? "" : file.split(".").pop().toLowerCase();
  58. }
  59. public function getDefaultContent() : haxe.io.Bytes {
  60. throw "Not implemented";
  61. return null;
  62. }
  63. override function setContainer(cont) {
  64. super.setContainer(cont);
  65. lastSaveTag = undo.currentID;
  66. undo.onChange = function() {
  67. modified = (undo.currentID != lastSaveTag);
  68. };
  69. keys.register("undo", function() undo.undo());
  70. keys.register("redo", function() undo.redo());
  71. keys.register("save", function() save());
  72. keys.register("view.refresh", function() rebuild());
  73. keys.register("view.refreshApp", function() untyped chrome.runtime.reload());
  74. }
  75. public function canSave() {
  76. return true;
  77. }
  78. public function save() {
  79. if( !canSave() )
  80. return;
  81. skipNextChange = true;
  82. modified = false;
  83. lastSaveTag = undo.currentID;
  84. }
  85. function saveBackup(content: String) {
  86. var tmpPath = ide.resourceDir + "/.tmp/" + state.path;
  87. var baseName = haxe.io.Path.withoutExtension(tmpPath);
  88. var tmpDir = haxe.io.Path.directory(tmpPath);
  89. // Save backup file
  90. try {
  91. sys.FileSystem.createDirectory(tmpDir);
  92. var dateFmt = DateTools.format(Date.now(), "%Y%m%d-%H%M%S");
  93. sys.io.File.saveContent(baseName + "-backup" + dateFmt + "." + haxe.io.Path.extension(state.path), content);
  94. }
  95. catch (e: Dynamic) {
  96. trace("Cannot save backup", e);
  97. }
  98. // Delete old files
  99. var allTemp = [];
  100. for( f in try sys.FileSystem.readDirectory(tmpDir) catch( e : Dynamic ) [] ) {
  101. if(~/-backup[0-9]{8}-[0-9]{6}$/.match(haxe.io.Path.withoutExtension(f))) {
  102. allTemp.push(f);
  103. }
  104. }
  105. allTemp.sort(Reflect.compare);
  106. if(allTemp.length > 10) {
  107. sys.FileSystem.deleteFile(tmpDir + "/" + allTemp[0]);
  108. }
  109. }
  110. public function saveAs() {
  111. ide.chooseFileSave(state.path, function(target) {
  112. state.path = target;
  113. save();
  114. skipNextChange = false;
  115. syncTitle();
  116. });
  117. }
  118. override function onBeforeClose() {
  119. if( modified && !js.Browser.window.confirm(state.path+" has been modified, quit without saving?") )
  120. return false;
  121. return super.onBeforeClose();
  122. }
  123. override function get_config() {
  124. if( config == null ) {
  125. if( state.path == null ) return super.get_config();
  126. config = hide.Config.loadForFile(ide, state.path);
  127. }
  128. return config;
  129. }
  130. function set_modified(b) {
  131. if( modified == b )
  132. return b;
  133. modified = b;
  134. syncTitle();
  135. return b;
  136. }
  137. function getPath() {
  138. return ide.getPath(state.path);
  139. }
  140. override function getTitle() {
  141. var parts = state.path.split("/");
  142. if( parts[parts.length - 1] == "" ) parts.pop(); // directory
  143. while( parts.length > 2 ) parts.shift();
  144. return parts.join(" / ")+(modified?" *":"");
  145. }
  146. override function syncTitle() {
  147. super.syncTitle();
  148. if( state.path != null )
  149. haxe.Timer.delay(function() if( container.tab != null ) container.tab.element.attr("title",getPath()), 100);
  150. }
  151. override function buildTabMenu() {
  152. var hasPath = state.path != null && state.path != "";
  153. var reloadItem : hide.comp.ContextMenu.ContextMenuItem = { label : "Reload", click : function() rebuild() };
  154. var arr : Array<hide.comp.ContextMenu.ContextMenuItem>;
  155. if( !hasPath && !canSave() ) {
  156. arr = [
  157. reloadItem,
  158. { label : null, isSeparator : true },
  159. ];
  160. }
  161. else {
  162. arr = [
  163. { label : "Save", enabled : canSave() && modified, click : function() { save(); modified = false; } },
  164. { label : "Save As...", enabled : canSave(), click : saveAs },
  165. { label : null, isSeparator : true },
  166. reloadItem,
  167. { label : "Explore", enabled : hasPath, click : function() { FileTree.exploreFile(getPath()); } },
  168. { label : "Copy Path", enabled : hasPath, click : function() { ide.setClipboard(state.path); } },
  169. { label : "Open in Resources", enabled : hasPath, click : function() {
  170. var filetree = ide.getViews(FileTree)[0];
  171. if( filetree != null ) {
  172. filetree.revealNode(state.path);
  173. }
  174. }},
  175. { label : null, isSeparator : true },
  176. ];
  177. }
  178. return arr.concat(super.buildTabMenu());
  179. }
  180. }