Window.vala 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. using Adw;
  2. using Gtk;
  3. namespace PpubViewer {
  4. public class ViewerWindow : Adw.ApplicationWindow {
  5. private Adw.HeaderBar header_bar;
  6. private Box box;
  7. private Flap flap;
  8. private DocumentView.DocumentViewManager document_view;
  9. private Button back_button;
  10. private Button forward_button;
  11. private Button properties_button;
  12. private Button menu_button;
  13. private PopoverMenu menu;
  14. private ZoomSpinButton zoom_spin;
  15. private Ppub.Publication publication;
  16. private NavigationHistoryItem current_page = null;
  17. private WindowTitle window_title;
  18. public ViewerWindow(Adw.Application app) {
  19. application = app;
  20. header_bar = new Adw.HeaderBar ();
  21. window_title = new WindowTitle("PPUB Viewer", "");
  22. flap = new Flap();
  23. box = new Box (Orientation.VERTICAL, 0);
  24. box.append (header_bar);
  25. box.append (flap);
  26. content = box;
  27. header_bar.show_end_title_buttons = true;
  28. default_width = 900;
  29. default_height = 700;
  30. header_bar.title_widget = window_title;
  31. flap.separator = new Separator(Orientation.VERTICAL);
  32. properties_button = new Button.from_icon_name("sidebar-show-symbolic");
  33. header_bar.pack_start(properties_button);
  34. header_bar.pack_start(new Separator(Orientation.VERTICAL));
  35. back_button = new Button.from_icon_name("go-previous-symbolic");
  36. back_button.sensitive = false;
  37. back_button.clicked.connect(go_back);
  38. header_bar.pack_start(back_button);
  39. forward_button = new Button.from_icon_name("go-next-symbolic");
  40. forward_button.sensitive = false;
  41. forward_button.clicked.connect(go_forward);
  42. header_bar.pack_start(forward_button);
  43. // menu = new PopoverMenu.from_model(null);
  44. // header_bar.pack_end(menu);
  45. // menu_button = new Button.from_icon_name("open-menu-symbolic");
  46. // menu_button.clicked.connect(() => menu.popup());
  47. // header_bar.pack_end(menu_button);
  48. var zoom_squeezer = new Squeezer();
  49. zoom_squeezer.transition_type = SqueezerTransitionType.CROSSFADE;
  50. zoom_spin = new ZoomSpinButton(false);
  51. var zoom_spin_small = new ZoomSpinButton(true);
  52. zoom_spin_small.adjustment = zoom_spin.adjustment;
  53. zoom_squeezer.add(zoom_spin);
  54. zoom_squeezer.add(zoom_spin_small);
  55. zoom_spin.zoom_level_changed.connect(change_zoom);
  56. header_bar.pack_end(zoom_squeezer);
  57. document_view = new DocumentView.DocumentViewManager();
  58. document_view.link_clicked.connect(link_clicked);
  59. flap.content = document_view;
  60. properties_button.clicked.connect(() => {
  61. flap.reveal_flap = !flap.reveal_flap;
  62. });
  63. }
  64. public void load_ppub(File file) throws Error {
  65. publication = new Ppub.Publication(file.get_path());
  66. var asset = publication.get_default_asset ();
  67. window_title.title = publication.metadata.title ?? "Untitled PPUB";
  68. window_title.subtitle = publication.metadata.author_name ?? "";
  69. title = window_title.title + " - PPUB Viewer";
  70. var scroller = new ScrolledWindow();
  71. scroller.add_css_class("background");
  72. scroller.hscrollbar_policy = PolicyType.NEVER;
  73. var pane = new PropertiesPane(publication.metadata, false);
  74. scroller.child = pane;
  75. pane.link_clicked.connect(property_link_clicked);
  76. flap.flap = scroller;
  77. navigate(asset.name);
  78. }
  79. public void navigate(string file) {
  80. if(current_page == null) {
  81. current_page = new NavigationHistoryItem();
  82. current_page.file_name = file;
  83. current_page.scroll_position = 0;
  84. }
  85. else {
  86. current_page = current_page.add_next(file, document_view.get_scroll_position());
  87. }
  88. load_document(file);
  89. }
  90. public void go_back() {
  91. current_page.scroll_position = document_view.get_scroll_position();
  92. current_page = current_page.previous;
  93. load_document(current_page.file_name);
  94. }
  95. public void go_forward() {
  96. current_page.scroll_position = document_view.get_scroll_position();
  97. current_page = current_page.next;
  98. load_document(current_page.file_name);
  99. }
  100. public void load_document(string file) {
  101. back_button.sensitive = current_page.previous != null;
  102. forward_button.sensitive = current_page.next != null;
  103. document_view.load_asset(publication, publication.get_asset(file));
  104. Idle.add_once(() => {
  105. document_view.set_scroll_position(current_page.scroll_position);
  106. return false;
  107. });
  108. }
  109. private void link_clicked(string url) {
  110. var asset = publication.get_asset(Uri.unescape_string(url));
  111. if(asset != null) {
  112. navigate(asset.name);
  113. return;
  114. }
  115. Uri uri;
  116. try{
  117. uri = Uri.parse(url, UriFlags.PARSE_RELAXED);
  118. }
  119. catch {
  120. var dialog = new Adw.MessageDialog(this, "Unrecognised link", @"Could not determine how to handle the link <i>$url</i>.");
  121. dialog.body_use_markup = true;
  122. dialog.add_response("close", "Close");
  123. dialog.present();
  124. dialog.response.connect(() => dialog.close());
  125. return;
  126. }
  127. var app = AppInfo.get_default_for_uri_scheme(uri.get_scheme());
  128. if(app == null) {
  129. var dialog = new Adw.MessageDialog(this, "No application", @"Could not find an application to handle the URI <i>$uri</i>.");
  130. dialog.body_use_markup = true;
  131. dialog.add_response("close", "Close");
  132. dialog.present();
  133. dialog.response.connect(() => dialog.close());
  134. return;
  135. }
  136. var uris = new List<string>();
  137. uris.append(uri.to_string());
  138. var dialog = new Adw.MessageDialog(this, "Open external link?", @"Do you want to open the external link <i>$uri</i>?");
  139. dialog.body_use_markup = true;
  140. dialog.add_response("cancel", @"Cancel");
  141. dialog.add_response("open", @"Open in $(app.get_display_name())");
  142. dialog.present();
  143. dialog.response.connect(id => {
  144. if(id == "open") {
  145. app.launch_uris(uris, null);
  146. }
  147. dialog.close();
  148. });
  149. }
  150. private void property_link_clicked(string file) {
  151. link_clicked(file);
  152. if(flap.folded) {
  153. flap.reveal_flap = false;
  154. }
  155. }
  156. private void change_zoom(int percent) {
  157. document_view.set_zoom_percentage(percent);
  158. }
  159. public override void size_allocate(int width, int height, int baseline) {
  160. base.size_allocate(width, height, baseline);
  161. document_view.reflow();
  162. }
  163. }
  164. }