1### Copyright (C) 2002-2006 Stephen Kennedy <stevek@gnome.org>
2### Copyright (C) 2011 Kai Willadsen <kai.willadsen@gmail.com>
3
4### This program is free software; you can redistribute it and/or modify
5### it under the terms of the GNU General Public License as published by
6### the Free Software Foundation; either version 2 of the License, or
7### (at your option) any later version.
8
9### This program is distributed in the hope that it will be useful,
10### but WITHOUT ANY WARRANTY; without even the implied warranty of
11### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12### GNU General Public License for more details.
13
14### You should have received a copy of the GNU General Public License
15### along with this program; if not, write to the Free Software
16### Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
17### USA.
18
19
20import subprocess
21import sys
22
23import gobject
24import gio
25import gtk
26
27from . import task
28
29from gettext import gettext as _
30
31
32class MeldDoc(gobject.GObject):
33    """Base class for documents in the meld application.
34    """
35
36    __gsignals__ = {
37        'label-changed':        (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
38                                 (gobject.TYPE_STRING, gobject.TYPE_STRING)),
39        'file-changed':         (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
40                                 (gobject.TYPE_STRING,)),
41        'create-diff':          (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
42                                 (gobject.TYPE_PYOBJECT,
43                                  gobject.TYPE_PYOBJECT)),
44        'status-changed':       (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
45                                 (gobject.TYPE_PYOBJECT,)),
46        'current-diff-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
47                                 ()),
48        'next-diff-changed':    (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
49                                 (bool, bool)),
50    }
51
52    def __init__(self, prefs):
53        gobject.GObject.__init__(self)
54        self.scheduler = task.FifoScheduler()
55        self.prefs = prefs
56        self.prefs.notify_add(self.on_preference_changed)
57        self.num_panes = 0
58        self.label_text = _("untitled")
59        self.tooltip_text = _("untitled")
60        self.status_info_labels = []
61
62    def get_info_widgets(self):
63        return self.status_info_labels
64
65    def get_comparison(self):
66        """Get the comparison type and path(s) being compared"""
67        pass
68
69    def save(self):
70        pass
71
72    def save_as(self):
73        pass
74
75    def stop(self):
76        if self.scheduler.tasks_pending():
77            self.scheduler.remove_task(self.scheduler.get_current_task())
78
79    def _open_files(self, selected, line=0):
80        query_attrs = ",".join((gio.FILE_ATTRIBUTE_STANDARD_TYPE,
81                                gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE))
82
83        def os_open(path):
84            if not path:
85                return
86            if sys.platform == "win32":
87                subprocess.Popen(["start", path], shell=True)
88            elif sys.platform == "darwin":
89                subprocess.Popen(["open", path])
90            else:
91                subprocess.Popen(["xdg-open", path])
92
93        def open_cb(source, result, *data):
94            info = source.query_info_finish(result)
95            file_type = info.get_file_type()
96            if file_type == gio.FILE_TYPE_DIRECTORY:
97                os_open(source.get_path())
98            elif file_type == gio.FILE_TYPE_REGULAR:
99                content_type = info.get_content_type()
100                path = source.get_path()
101                # FIXME: Content types are broken on Windows with current gio
102                if gio.content_type_is_a(content_type, "text/plain") or \
103                        sys.platform == "win32":
104                    editor = self.prefs.get_editor_command(path, line)
105                    if editor:
106                        subprocess.Popen(editor)
107                    else:
108                        os_open(path)
109                else:
110                    os_open(path)
111            else:
112                # TODO: Add some kind of 'failed to open' notification
113                pass
114
115        for f in [gio.File(s) for s in selected]:
116            f.query_info_async(query_attrs, open_cb)
117
118    def open_external(self):
119        pass
120
121    def on_refresh_activate(self, *extra):
122        pass
123
124    def on_find_activate(self, *extra):
125        pass
126
127    def on_find_next_activate(self, *extra):
128        pass
129
130    def on_find_previous_activate(self, *extra):
131        pass
132
133    def on_replace_activate(self, *extra):
134        pass
135
136    def on_preference_changed(self, key, value):
137        pass
138
139    def on_file_changed(self, filename):
140        pass
141
142    def label_changed(self):
143        self.emit("label-changed", self.label_text, self.tooltip_text)
144
145    def set_labels(self, lst):
146        pass
147
148    def on_container_switch_in_event(self, uimanager):
149        """Called when the container app switches to this tab.
150        """
151        self.ui_merge_id = uimanager.add_ui_from_file(self.ui_file)
152        uimanager.insert_action_group(self.actiongroup, -1)
153        self.popup_menu = uimanager.get_widget("/Popup")
154        uimanager.ensure_update()
155        if hasattr(self, "focus_pane") and self.focus_pane:
156            self.scheduler.add_task(self.focus_pane.grab_focus)
157
158    def on_container_switch_out_event(self, uimanager):
159        """Called when the container app switches away from this tab.
160        """
161        uimanager.remove_action_group(self.actiongroup)
162        uimanager.remove_ui(self.ui_merge_id)
163
164    def on_delete_event(self, appquit=0):
165        """Called when the docs container is about to close.
166
167        A doc normally returns gtk.RESPONSE_OK, but may instead return
168        gtk.RESPONSE_CANCEL to request that the container not delete it.
169        """
170        return gtk.RESPONSE_OK
171