~umang/indicator-stickynotes/trunk

« back to all changes in this revision

Viewing changes to indicator-stickynotes.py

  • Committer: Umang Varma
  • Date: 2022-03-12 23:34:38 UTC
  • Revision ID: git-v1:5c567b9671f55f67086ff6aba645c3fed424813a
Bump version 0.5.9 -> 0.5.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python3
2
2
3
 
# Copyright © 2012 Umang Varma <umang.me@gmail.com>
 
3
# Copyright © 2012-2016 Umang Varma <umang.me@gmail.com>
4
4
5
5
# This file is part of indicator-stickynotes.
6
6
18
18
# indicator-stickynotes.  If not, see <http://www.gnu.org/licenses/>.
19
19
 
20
20
from stickynotes.backend import Note, NoteSet
21
 
from stickynotes.gui import StickyNote
 
21
from stickynotes.gui import *
 
22
import stickynotes.info
22
23
from stickynotes.info import MO_DIR, LOCALE_DOMAIN
23
24
 
 
25
import gi
 
26
gi.require_version('Gtk', '3.0')
 
27
gi.require_version('GtkSource', '3.0')
 
28
gi.require_version('AppIndicator3', '0.1')
24
29
from gi.repository import Gtk, Gdk
25
30
from gi.repository import AppIndicator3 as appindicator
26
31
 
27
32
import os.path
28
33
import locale
 
34
import argparse
29
35
from locale import gettext as _
30
36
from functools import wraps
 
37
from shutil import copyfile, SameFileError
 
38
 
 
39
import socket
 
40
import sys
31
41
 
32
42
def save_required(f):
33
43
    """Wrapper for functions that require a save after execution"""
39
49
    return _wrapper
40
50
 
41
51
class IndicatorStickyNotes:
42
 
    def __init__(self):
 
52
    def __init__(self, args = None):
 
53
        self.args = args
 
54
        # use development data file if requested
 
55
        isdev = args and args.d
 
56
        self.data_file = stickynotes.info.DEBUG_SETTINGS_FILE if isdev \
 
57
                else stickynotes.info.SETTINGS_FILE
43
58
        # Initialize NoteSet
44
 
        self.nset = NoteSet(StickyNote)
45
 
        self.nset.open()
46
 
        self.nset.showall()
 
59
        self.nset = NoteSet(StickyNote, self.data_file, self)
 
60
        try:
 
61
            self.nset.open()
 
62
        except FileNotFoundError:
 
63
            self.nset.load_fresh()
 
64
        except Exception as e:
 
65
            err = _("Error reading data file. Do you want to "
 
66
                "backup the current data?")
 
67
            winError = Gtk.MessageDialog(None, None, Gtk.MessageType.ERROR,
 
68
                    Gtk.ButtonsType.NONE, err)
 
69
            winError.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT,
 
70
                    _("Backup"), Gtk.ResponseType.ACCEPT)
 
71
            winError.set_title(_("Indicator Stickynotes"))
 
72
            resp = winError.run()
 
73
            winError.hide()
 
74
            if resp == Gtk.ResponseType.ACCEPT:
 
75
                self.backup_datafile()
 
76
            winError.destroy()
 
77
            self.nset.load_fresh()
 
78
 
 
79
        # If all notes were visible previously, show them now
 
80
        if self.nset.properties.get("all_visible", True):
 
81
            self.nset.showall()
47
82
        # Create App Indicator
48
83
        self.ind = appindicator.Indicator.new(
49
84
                "Sticky Notes", "indicator-stickynotes",
51
86
        # Delete/modify the following file when distributing as a package
52
87
        self.ind.set_icon_theme_path(os.path.abspath(os.path.join(
53
88
            os.path.dirname(__file__), 'Icons')))
54
 
        self.ind.set_icon("indicator-stickynotes")
 
89
        self.ind.set_icon("indicator-stickynotes-mono")
55
90
        self.ind.set_status(appindicator.IndicatorStatus.ACTIVE)
56
91
        self.ind.set_title(_("Sticky Notes"))
57
92
        # Create Menu
93
128
        self.menu.append(s)
94
129
        s.show()
95
130
 
 
131
        self.mExport = Gtk.MenuItem(_("Export Data"))
 
132
        self.menu.append(self.mExport)
 
133
        self.mExport.connect("activate", self.export_datafile, None)
 
134
        self.mExport.show()
 
135
 
 
136
        self.mImport = Gtk.MenuItem(_("Import Data"))
 
137
        self.menu.append(self.mImport)
 
138
        self.mImport.connect("activate", self.import_datafile, None)
 
139
        self.mImport.show()
 
140
 
 
141
        s = Gtk.SeparatorMenuItem.new()
 
142
        self.menu.append(s)
 
143
        s.show()
 
144
 
 
145
        self.mAbout = Gtk.MenuItem(_("About"))
 
146
        self.menu.append(self.mAbout)
 
147
        self.mAbout.connect("activate", self.show_about, None)
 
148
        self.mAbout.show()
 
149
 
 
150
        self.mSettings = Gtk.MenuItem(_("Settings"))
 
151
        self.menu.append(self.mSettings)
 
152
        self.mSettings.connect("activate", self.show_settings, None)
 
153
        self.mSettings.show()
 
154
 
 
155
        s = Gtk.SeparatorMenuItem.new()
 
156
        self.menu.append(s)
 
157
        s.show()
 
158
 
96
159
        self.mQuit = Gtk.MenuItem(_("Quit"))
97
160
        self.menu.append(self.mQuit)
98
161
        self.mQuit.connect("activate", Gtk.main_quit, None)
100
163
        # Connect Indicator to menu
101
164
        self.ind.set_menu(self.menu)
102
165
 
 
166
        # Define secondary action (middle click)
 
167
        self.connect_secondary_activate()
 
168
 
103
169
    def new_note(self, *args):
104
170
        self.nset.new()
105
171
 
106
172
    def showall(self, *args):
107
173
        self.nset.showall(*args)
 
174
        self.connect_secondary_activate()
108
175
 
109
176
    def hideall(self, *args):
110
177
        self.nset.hideall()
 
178
        self.connect_secondary_activate()
 
179
 
 
180
    def connect_secondary_activate(self):
 
181
        """Define action of secondary action (middle click) depending
 
182
        on visibility state of notes."""
 
183
        if self.nset.properties["all_visible"] == True:
 
184
            self.ind.set_secondary_activate_target(self.mHideAll)
 
185
        else:
 
186
            self.ind.set_secondary_activate_target(self.mShowAll)
 
187
 
111
188
 
112
189
    @save_required
113
190
    def lockall(self, *args):
114
191
        for note in self.nset.notes:
115
 
            note.gui.set_locked_state(True)
 
192
            note.set_locked_state(True)
116
193
        
117
194
    @save_required
118
195
    def unlockall(self, *args):
119
196
        for note in self.nset.notes:
120
 
            note.gui.set_locked_state(False)
 
197
            note.set_locked_state(False)
 
198
 
 
199
    def backup_datafile(self):
 
200
        winChoose = Gtk.FileChooserDialog(_("Export Data"), None,
 
201
                Gtk.FileChooserAction.SAVE, (Gtk.STOCK_CANCEL,
 
202
                    Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE,
 
203
                    Gtk.ResponseType.ACCEPT))
 
204
        winChoose.set_do_overwrite_confirmation(True)
 
205
        response = winChoose.run()
 
206
        backupfile = None
 
207
        if response == Gtk.ResponseType.ACCEPT:
 
208
            backupfile =  winChoose.get_filename()
 
209
        winChoose.destroy()
 
210
        if backupfile:
 
211
            try:
 
212
                copyfile(os.path.expanduser(self.data_file), backupfile)
 
213
            except SameFileError:
 
214
                err = _("Please choose a different "
 
215
                    "destination for the backup file.")
 
216
                winError = Gtk.MessageDialog(None, None,
 
217
                        Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, err)
 
218
                winError.run()
 
219
                winError.destroy()
 
220
                self.backup_datafile()
 
221
 
 
222
    def export_datafile(self, *args):
 
223
        self.backup_datafile()
 
224
 
 
225
    def import_datafile(self, *args):
 
226
        winChoose = Gtk.FileChooserDialog(_("Import Data"), None,
 
227
                Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL,
 
228
                    Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
 
229
                    Gtk.ResponseType.ACCEPT))
 
230
        response = winChoose.run()
 
231
        backupfile = None
 
232
        if response == Gtk.ResponseType.ACCEPT:
 
233
            backupfile =  winChoose.get_filename()
 
234
        winChoose.destroy()
 
235
        if backupfile:
 
236
            try:
 
237
                with open(backupfile, encoding="utf-8") as fsock:
 
238
                    self.nset.merge(fsock.read())
 
239
            except Exception as e:
 
240
                err = _("Error importing data.")
 
241
                winError = Gtk.MessageDialog(None, None,
 
242
                        Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, err)
 
243
                winError.run()
 
244
                winError.destroy()
 
245
 
 
246
    def show_about(self, *args):
 
247
        show_about_dialog()
 
248
 
 
249
    def show_settings(self, *args):
 
250
        wSettings = SettingsDialog(self.nset)
121
251
 
122
252
    def save(self):
123
253
        self.nset.save()
124
254
 
125
 
 
126
255
def main():
 
256
    # Avoid duplicate process
 
257
    # From https://stackoverflow.com/questions/788411/check-to-see-if-python-script-is-running
 
258
    procLock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
 
259
    try:
 
260
        procLock.bind('\0' + 'indicator-stickynotes')
 
261
    except socket.error:
 
262
        print('Indicator stickynotes already running.')
 
263
        sys.exit()
 
264
 
127
265
    try:
128
266
        locale.setlocale(locale.LC_ALL, '')
129
267
    except:
133
271
        # Fallback to default
134
272
        locale_dir = None
135
273
    else:
136
 
        locale_dir = MO_DIR
 
274
        locale_dir = os.path.join(os.path.dirname(__file__), MO_DIR)
137
275
    locale.bindtextdomain(LOCALE_DOMAIN, locale_dir)
138
276
    locale.textdomain(LOCALE_DOMAIN)
139
 
    indicator = IndicatorStickyNotes()
 
277
 
 
278
    parser = argparse.ArgumentParser(description=_("Sticky Notes"))
 
279
    parser.add_argument("-d", action='store_true', help="use the development"
 
280
            " data file")
 
281
    args = parser.parse_args()
 
282
 
 
283
    indicator = IndicatorStickyNotes(args)
 
284
    # Load global css for the first time.
 
285
    load_global_css()
140
286
    Gtk.main()
141
287
    indicator.save()
142
288