1/*
2* Copyright (c) 2019-2020 Alecaddd (https://alecaddd.com)
3*
4* This file is part of Akira.
5*
6* Akira is free software: you can redistribute it and/or modify
7* it under the terms of the GNU General Public License as published by
8* the Free Software Foundation, either version 3 of the License, or
9* (at your option) any later version.
10
11* Akira is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15
16* You should have received a copy of the GNU General Public License
17* along with Akira. If not, see <https://www.gnu.org/licenses/>.
18*
19* Authored by: Alessandro "Alecaddd" Castellani <castellani.ale@gmail.com>
20*/
21
22public class Akira.Window : Gtk.ApplicationWindow {
23    public FileFormat.AkiraFile? akira_file = null;
24    public FileFormat.FileManager file_manager;
25
26    public weak Akira.Application app { get; construct; }
27    public Akira.Services.EventBus event_bus;
28    public Akira.Lib.Managers.ItemsManager items_manager;
29
30    public Akira.Services.ActionManager action_manager;
31    public Akira.Layouts.HeaderBar headerbar;
32    public Akira.Layouts.MainWindow main_window;
33    public Akira.Utils.Dialogs dialogs;
34
35    public Akira.StateManagers.CoordinatesMiddleware coords_middleware;
36    public Akira.StateManagers.SizeMiddleware size_middleware;
37
38    public SimpleActionGroup actions { get; construct; }
39    public Gtk.AccelGroup accel_group { get; construct; }
40
41    public bool edited { get; set; default = false; }
42
43    public Window (Akira.Application akira_app) {
44        Object (
45            application: akira_app,
46            app: akira_app,
47            icon_name: "com.github.akiraux.akira"
48        );
49    }
50
51    construct {
52        accel_group = new Gtk.AccelGroup ();
53        add_accel_group (accel_group);
54
55        event_bus = new Akira.Services.EventBus ();
56        items_manager = new Akira.Lib.Managers.ItemsManager (this);
57        action_manager = new Akira.Services.ActionManager (app, this);
58        file_manager = new Akira.FileFormat.FileManager (this);
59        headerbar = new Akira.Layouts.HeaderBar (this);
60        main_window = new Akira.Layouts.MainWindow (this);
61        coords_middleware = new Akira.StateManagers.CoordinatesMiddleware (this);
62        size_middleware = new Akira.StateManagers.SizeMiddleware (this);
63        dialogs = new Akira.Utils.Dialogs (this);
64
65        build_ui ();
66
67        move (settings.pos_x, settings.pos_y);
68
69        show_app ();
70
71        // Let the canvas grab the focus after the app is visible.
72        main_window.main_canvas.canvas.focus_canvas ();
73
74        event_bus.file_edited.connect (on_file_edited);
75        event_bus.file_saved.connect (on_file_saved);
76    }
77
78    private void build_ui () {
79        set_titlebar (headerbar);
80        set_border_width (0);
81        if (Constants.PROFILE == "development") {
82            headerbar.get_style_context ().add_class ("devel");
83        }
84
85        delete_event.connect ((e) => {
86            return before_destroy ();
87        });
88
89        add (main_window);
90    }
91
92    private void apply_user_settings () {
93        Gtk.Settings.get_default ().gtk_application_prefer_dark_theme = settings.dark_theme;
94
95        var css_provider = new Gtk.CssProvider ();
96        css_provider.load_from_resource ("/com/github/akiraux/akira/stylesheet.css");
97
98        Gtk.StyleContext.add_provider_for_screen (
99            Gdk.Screen.get_default (), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
100        );
101
102        resize (settings.window_width, settings.window_height);
103        main_window.pane.position = settings.left_paned;
104        main_window.pane2.position = settings.right_paned;
105    }
106
107    private void on_file_edited () {
108        edited = true;
109    }
110
111    private void on_file_saved () {
112        edited = false;
113    }
114
115    public bool before_destroy () {
116        update_status ();
117
118        if (!edited) {
119            close_current_file ();
120            app.get_active_window ().destroy ();
121            on_destroy ();
122        }
123
124        if (edited) {
125            var dialog = dialogs.message_dialog (
126                _("Are you sure you want to quit?"),
127                _("All unsaved data will be lost and impossible to recover."),
128                "system-shutdown",
129                _("Quit without saving!"),
130                _("Save file")
131            );
132
133            dialog.show_all ();
134
135            dialog.response.connect ((id) => {
136                switch (id) {
137                    case Gtk.ResponseType.ACCEPT:
138                        dialog.destroy ();
139                        close_current_file ();
140                        app.get_active_window ().destroy ();
141                        on_destroy ();
142                        break;
143                    case 2:
144                        dialog.destroy ();
145                        file_manager.save_file ();
146                        break;
147                    default:
148                        dialog.destroy ();
149                        break;
150                }
151            });
152
153            dialog.run ();
154        }
155
156        return true;
157    }
158
159    public void on_destroy () {
160        uint length = app.windows.length ();
161
162        if (length == 0) {
163            app.quit ();
164        }
165    }
166
167    private void update_status () {
168        int width, height, x, y;
169
170        get_size (out width, out height);
171        get_position (out x, out y);
172
173        settings.pos_x = x;
174        settings.pos_y = y;
175        settings.window_width = width;
176        settings.window_height = height;
177        settings.left_paned = main_window.pane.get_position ();
178        settings.right_paned = main_window.pane2.get_position ();
179    }
180
181    public void show_app () {
182        apply_user_settings ();
183        show_all ();
184        show ();
185        present ();
186    }
187
188    public void open_file (File file) {
189        akira_file = new FileFormat.AkiraFile (file, this);
190
191        akira_file.prepare ();
192        akira_file.load_file ();
193    }
194
195    public void save_new_file (File file, bool overwrite = false) {
196        akira_file = new FileFormat.AkiraFile (file, this);
197        akira_file.overwrite = overwrite;
198
199        akira_file.prepare ();
200        akira_file.save_file ();
201    }
202
203    private void close_current_file () {
204        if (akira_file != null) {
205            akira_file.close ();
206        }
207    }
208}
209