Editor.vala 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. using Adw;
  2. using Gtk;
  3. namespace Publicate {
  4. public class PpubEditor : Box {
  5. private Adw.HeaderBar header;
  6. private WindowTitle header_title;
  7. private Leaflet leaflet;
  8. private Ppub.Publication publication;
  9. private File publication_file;
  10. private ViewerWindow window;
  11. private FileExplorer file_explorer;
  12. private Box tab_box;
  13. private TabView tab_view;
  14. private TabBar tab_bar;
  15. private Button save_tab_button;
  16. private Gee.HashMap<string, Editors.EditorWidget> open_editors = new Gee.HashMap<string, Editors.EditorWidget>();
  17. public PpubEditor(ViewerWindow win) {
  18. window = win;
  19. orientation = Orientation.VERTICAL;
  20. header = new Adw.HeaderBar();
  21. append(header);
  22. header_title = new WindowTitle("Untitled Publication", "");
  23. header.title_widget = header_title;
  24. var file_box = new Box(Orientation.VERTICAL, 0);
  25. file_box.vexpand = true;
  26. file_explorer = new FileExplorer();
  27. file_explorer.asset_selected.connect(open_asset);
  28. file_explorer.vexpand = true;
  29. file_box.append(file_explorer);
  30. var file_buttons = new Box(Orientation.HORIZONTAL, 0);
  31. file_buttons.add_css_class("linked");
  32. file_buttons.halign = Align.END;
  33. file_buttons.margin_end = 8;
  34. file_buttons.margin_bottom = 8;
  35. file_buttons.margin_start = 8;
  36. file_buttons.margin_top = 8;
  37. file_box.append(file_buttons);
  38. var new_file_button = new Button.from_icon_name("document-new-symbolic");
  39. file_buttons.append(new_file_button);
  40. var add_file_button = new Button.from_icon_name("list-add-symbolic");
  41. file_buttons.append(add_file_button);
  42. var remove_file_button = new Button.from_icon_name("user-trash-symbolic");
  43. file_buttons.append(remove_file_button);
  44. leaflet = new Leaflet();
  45. leaflet.vexpand = true;
  46. leaflet.append(file_box);
  47. tab_view = new TabView();
  48. tab_bar = new TabBar();
  49. tab_box = new Box(Orientation.VERTICAL, 0);
  50. tab_bar.autohide = false;
  51. tab_bar.set_view(tab_view);
  52. tab_box.append(tab_bar);
  53. tab_box.append(tab_view);
  54. leaflet.append(tab_box);
  55. save_tab_button = new Button.from_icon_name("document-save-symbolic");
  56. save_tab_button.clicked.connect(save_tab);
  57. header.pack_end(save_tab_button);
  58. tab_view.notify["selected-page"].connect(() => select_file_from_tab());
  59. append(leaflet);
  60. }
  61. public async void load_ppub(File file) throws Error {
  62. publication = new Ppub.Publication(file.get_path());
  63. publication_file = file;
  64. header_title.title = publication.metadata.title ?? "Untitled PPUB";
  65. header_title.subtitle = publication.metadata.author_name ?? "";
  66. window.title = header_title.title + " - Publicate!";
  67. file_explorer.set_assets(publication.assets);
  68. }
  69. public async void open_asset(Ppub.Asset asset) {
  70. if(open_editors.has_key(asset.name)) {
  71. tab_view.selected_page = open_editors[asset.name].tab_page;
  72. return;
  73. }
  74. if(asset.mimetype == "text/markdown") {
  75. var editor = new Editors.MarkdownEditor(window, tab_view);
  76. add_editor(editor, asset);
  77. }
  78. else if(asset.mimetype.has_prefix("text/")) {
  79. var editor = new Editors.PlainTextEditor(window, tab_view);
  80. add_editor(editor, asset);
  81. }
  82. if(asset.mimetype == "application/x-ppub-metadata") {
  83. var editor = new Editors.MetadataEditor(window, tab_view);
  84. add_editor(editor, asset);
  85. }
  86. }
  87. private void add_editor(Editors.EditorWidget editor, Ppub.Asset asset) {
  88. editor.load_asset(publication, asset);
  89. open_editors.set(asset.name, editor);
  90. tab_view.selected_page = editor.tab_page;
  91. }
  92. private async void save(Invercargill.Enumerable<Savable> to_save) {
  93. var builder = new Ppub.Builder();
  94. foreach (var item in to_save) {
  95. item.save_asset(builder);
  96. }
  97. var temp_file = File.new_for_path(publication_file.get_path() + ".tmp");
  98. var stream = yield temp_file.replace_async(null, false, FileCreateFlags.REPLACE_DESTINATION, Priority.DEFAULT);
  99. builder.write(stream);
  100. yield stream.close_async(Priority.DEFAULT, null);
  101. yield temp_file.move_async(publication_file, FileCopyFlags.OVERWRITE, Priority.DEFAULT, null, null);
  102. yield load_ppub(publication_file);
  103. select_file_from_tab();
  104. }
  105. private async void save_tab() {
  106. var current_editor = (Editors.EditorWidget)tab_view.selected_page.child;
  107. var to_save = publication.assets.select<Savable>(a => a.name == current_editor.asset_name ? (Savable)current_editor : new SavableAsset(publication, a));
  108. yield save(to_save);
  109. }
  110. private void select_file_from_tab() {
  111. var editor = (Editors.EditorWidget)tab_view.selected_page.child;
  112. file_explorer.set_selected_item(editor.asset_name);
  113. }
  114. public async void add_asset (string name, string mimetype, GLib.InputStream stream, Ppub.CompressionInfo compression) {
  115. var to_save = publication.assets.select<Savable>(a => new SavableAsset(publication, a)).to_sequence();
  116. to_save.add(new SavableNewAsset(name, mimetype, stream, compression));
  117. yield save(to_save);
  118. }
  119. }
  120. }