Erik Grinaker is sharing code with you
Bitbucket is a code hosting site. Unlimited public and private repositories. Free for small teams.
Don't show this againRevelation / src / revelation
- commit
- 7d9375f894bb
- parent
- f4e8220f0a3a
- branch
- default
- tags
- revelation-0.3.1
set release date
1 |
cea4127a11c0
|
#!/usr/bin/env python |
2 |
cea4127a11c0
|
|
3 |
cea4127a11c0
|
# |
4 |
f5321aba18db
|
# Revelation 0.3.1 - a password manager for GNOME 2 |
5 |
b181693cfdc7
|
# http://oss.codepoet.no/revelation/ |
6 |
dc69203e823e
|
# $Id$ |
7 |
cea4127a11c0
|
# |
8 |
cea4127a11c0
|
# Copyright (c) 2003-2004 Erik Grinaker |
9 |
cea4127a11c0
|
# |
10 |
cea4127a11c0
|
# This program is free software; you can redistribute it and/or |
11 |
cea4127a11c0
|
# modify it under the terms of the GNU General Public License |
12 |
cea4127a11c0
|
# as published by the Free Software Foundation; either version 2 |
13 |
cea4127a11c0
|
# of the License, or (at your option) any later version. |
14 |
cea4127a11c0
|
# |
15 |
cea4127a11c0
|
# This program is distributed in the hope that it will be useful, |
16 |
cea4127a11c0
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 |
cea4127a11c0
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 |
cea4127a11c0
|
# GNU General Public License for more details. |
19 |
cea4127a11c0
|
# |
20 |
cea4127a11c0
|
# You should have received a copy of the GNU General Public License |
21 |
cea4127a11c0
|
# along with this program; if not, write to the Free Software |
22 |
cea4127a11c0
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
23 |
cea4127a11c0
|
# |
24 |
cea4127a11c0
|
|
25 |
cea4127a11c0
|
import pygtk |
26 |
cea4127a11c0
|
pygtk.require("2.0") |
27 |
9b3c9903350d
|
|
28 |
9b3c9903350d
|
import gtk, gnome, revelation, os, os.path, sys, gobject |
29 |
cea4127a11c0
|
|
30 |
2fd8a0ec71c3
|
|
31 |
0f15e637f284
|
class Revelation(revelation.widget.App): |
32 |
0f15e637f284
|
"Main application class" |
33 |
cea4127a11c0
|
|
34 |
cea4127a11c0
|
def __init__(self): |
35 |
0f15e637f284
|
gnome.init(revelation.APPNAME, revelation.APPNAME) |
36 |
a877d43f0987
|
revelation.widget.App.__init__(self, revelation.APPNAME) |
37 |
cea4127a11c0
|
|
38 |
a877d43f0987
|
os.umask(0077) |
39 |
cea4127a11c0
|
|
40 |
0f15e637f284
|
gtk.window_set_default_icon_list( |
41 |
0f15e637f284
|
gtk.gdk.pixbuf_new_from_file(revelation.DATADIR + "/pixmaps/revelation.png"), |
42 |
0f15e637f284
|
gtk.gdk.pixbuf_new_from_file(revelation.DATADIR + "/pixmaps/revelation-16x16.png") |
43 |
0f15e637f284
|
) |
44 |
cea4127a11c0
|
|
45 |
0f15e637f284
|
self.__init_facilities() |
46 |
0f15e637f284
|
self.__init_toolbar() |
47 |
0f15e637f284
|
self.__init_menu() |
48 |
0f15e637f284
|
self.__init_mainarea() |
49 |
0f15e637f284
|
self.__init_states() |
50 |
0f15e637f284
|
|
51 |
0f15e637f284
|
|
52 |
b181693cfdc7
|
# init methods |
53 |
0f15e637f284
|
def __init_facilities(self): |
54 |
0f15e637f284
|
"Sets up various application facilities" |
55 |
0f15e637f284
|
|
56 |
5c5c063d3896
|
try: |
57 |
f54fce826711
|
self.config = revelation.data.Config() |
58 |
5c5c063d3896
|
|
59 |
5c5c063d3896
|
except revelation.data.ConfigError: |
60 |
5c5c063d3896
|
revelation.dialog.Error( |
61 |
5c5c063d3896
|
None, "Configuration error", |
62 |
5c5c063d3896
|
"The Revelation configuration data could not be found in gconf. This indicates a fault in your installation, please re-install Revelation." |
63 |
5c5c063d3896
|
).run() |
64 |
5c5c063d3896
|
|
65 |
5c5c063d3896
|
sys.exit(1) |
66 |
5c5c063d3896
|
|
67 |
5c5c063d3896
|
|
68 |
0f15e637f284
|
self.icons = revelation.stock.IconFactory(self) |
69 |
0f15e637f284
|
self.data = revelation.data.EntryStore() |
70 |
0f15e637f284
|
self.clipboard = revelation.data.EntryClipboard() |
71 |
0f15e637f284
|
self.undoqueue = revelation.data.UndoQueue(self.data) |
72 |
0f15e637f284
|
self.finder = revelation.data.EntrySearch(self.data) |
73 |
0f15e637f284
|
|
74 |
a877d43f0987
|
self.data.connect("file-changed", self.__cb_state_file) |
75 |
a877d43f0987
|
|
76 |
0f15e637f284
|
self.clipboard.connect("copy", self.__cb_state_clipboard) |
77 |
0f15e637f284
|
self.clipboard.connect("cut", self.__cb_state_clipboard) |
78 |
0f15e637f284
|
|
79 |
0f15e637f284
|
self.undoqueue.connect("changed", self.__cb_state_undo) |
80 |
0f15e637f284
|
|
81 |
0f15e637f284
|
self.finder.connect("changed", self.__cb_state_find) |
82 |
0f15e637f284
|
|
83 |
0f15e637f284
|
|
84 |
0f15e637f284
|
def __init_mainarea(self): |
85 |
0f15e637f284
|
"Sets up the main application area" |
86 |
0f15e637f284
|
|
87 |
fd5f1af41bae
|
self.tree = revelation.widget.Tree(self.data) |
88 |
b181693cfdc7
|
self.tree.connect("popup", self.__cb_popup_tree) |
89 |
a877d43f0987
|
self.tree.connect("doubleclick", lambda w,d: self.entry_edit()) |
90 |
a877d43f0987
|
self.tree.selection.connect("changed", lambda w: self.dataview.display_entry(self.data.get_entry(self.tree.get_active()))) |
91 |
0f15e637f284
|
self.tree.selection.connect("changed", self.__cb_state_entry) |
92 |
0f15e637f284
|
scrolledwindow = revelation.widget.ScrolledWindow(self.tree) |
93 |
cea4127a11c0
|
|
94 |
fd5f1af41bae
|
self.dataview = revelation.widget.DataView() |
95 |
0f15e637f284
|
alignment = gtk.Alignment(0.5, 0.4, 0, 0) |
96 |
0f15e637f284
|
alignment.add(self.dataview) |
97 |
cea4127a11c0
|
|
98 |
9b3c9903350d
|
self.hpaned = revelation.widget.HPaned(scrolledwindow, alignment, self.config.get("view/pane-position")) |
99 |
0f15e637f284
|
self.set_contents(self.hpaned) |
100 |
0f15e637f284
|
|
101 |
0f15e637f284
|
|
102 |
0f15e637f284
|
def __init_menu(self): |
103 |
0f15e637f284
|
"Sets up the application menu" |
104 |
0f15e637f284
|
|
105 |
a877d43f0987
|
self.create_menu(( |
106 |
0f15e637f284
|
("/_File", None, None, None, 0, "<Branch>"), |
107 |
0f15e637f284
|
("/File/_New", "<Control>N", "Create a new file", lambda w,d: self.file_new(), 0, "<StockItem>", gtk.STOCK_NEW), |
108 |
0f15e637f284
|
("/File/_Open...", "<Control>O", "Open a file", lambda w,d: self.file_open(), 0, "<StockItem>", gtk.STOCK_OPEN), |
109 |
0f15e637f284
|
("/File/sep1", None, None, None, 0, "<Separator>"), |
110 |
a877d43f0987
|
("/File/_Save", "<Control>S", "Save data to file", lambda w,d: self.file_save(self.data.file, self.data.password), 0, "<StockItem>", gtk.STOCK_SAVE), |
111 |
0f15e637f284
|
("/File/Save _As...", "<Shift><Control>S", "Save data to different file", lambda w,d: self.file_save(), 0, "<StockItem>", gtk.STOCK_SAVE_AS), |
112 |
0f15e637f284
|
("/File/_Revert", None, "Revert to the saved copy of the file", lambda w,d: self.file_revert(), 0, "<StockItem>", gtk.STOCK_REVERT_TO_SAVED), |
113 |
0f15e637f284
|
("/File/sep2", None, None, None, 0, "<Separator>"), |
114 |
0f15e637f284
|
("/File/Change _Password...", None, "Change password of current file", lambda w,d: self.change_password(), 0, "<StockItem>", revelation.stock.STOCK_PASSWORD), |
115 |
0f15e637f284
|
("/File/_Lock...", "<Control>L", "Lock the current data file", lambda w,d: self.file_lock(), 0, "<StockItem>", revelation.stock.STOCK_LOCK), |
116 |
0f15e637f284
|
("/File/sep3", None, None, None, 0, "<Separator>"), |
117 |
0f15e637f284
|
("/File/_Import...", None, "Import data from a foreign file", lambda w,d: self.file_import(), 0, "<StockItem>", revelation.stock.STOCK_IMPORT), |
118 |
0f15e637f284
|
("/File/_Export...", None, "Export data to a different format", lambda w,d: self.file_export(), 0, "<StockItem>", revelation.stock.STOCK_EXPORT), |
119 |
0f15e637f284
|
("/File/sep4", None, None, None, 0, "<Separator>"), |
120 |
a877d43f0987
|
("/File/_Close", "<Control>W", "Close the application", lambda w,d: self.quit(), 0, "<StockItem>", gtk.STOCK_CLOSE), |
121 |
a877d43f0987
|
("/File/_Quit", "<Control>Q", "Quit the application", lambda w,d: self.quit(), 0, "<StockItem>", gtk.STOCK_QUIT), |
122 |
0f15e637f284
|
|
123 |
0f15e637f284
|
("/_Edit", None, None, None, 0, "<Branch>"), |
124 |
0f15e637f284
|
("/Edit/_Add Entry...", "Insert", "Create a new entry", lambda w,d: self.entry_add(), 0, "<StockItem>", revelation.stock.STOCK_ADD), |
125 |
0f15e637f284
|
("/Edit/_Edit", "Return", "Edit the selected entry", lambda w,d: self.entry_edit(), 0, "<StockItem>", revelation.stock.STOCK_EDIT), |
126 |
0f15e637f284
|
("/Edit/Re_move", "Delete", "Remove the selected entry", lambda w,d: self.entry_remove(), 0, "<StockItem>", revelation.stock.STOCK_REMOVE), |
127 |
0f15e637f284
|
("/Edit/sep1", None, None, None, 0, "<Separator>"), |
128 |
0f15e637f284
|
("/Edit/_Undo", "<Control>Z", "Undo the last action", lambda w,d: self.undo(), 0, "<StockItem>", gtk.STOCK_UNDO), |
129 |
0f15e637f284
|
("/Edit/_Redo", "<Shift><Control>Z", "Redo the previously undone action", lambda w,d: self.redo(), 0, "<StockItem>", gtk.STOCK_REDO), |
130 |
0f15e637f284
|
("/Edit/sep2", None, None, None, 0, "<Separator>"), |
131 |
0f15e637f284
|
("/Edit/Cu_t", "<Control>X", "Cut the entry to the clipboard", lambda w,d: self.clip_cut(), 0, "<StockItem>", gtk.STOCK_CUT), |
132 |
0f15e637f284
|
("/Edit/_Copy", "<Control>C", "Copy the entry to the clipboard", lambda w,d: self.clip_copy(), 0, "<StockItem>", gtk.STOCK_COPY), |
133 |
0f15e637f284
|
("/Edit/_Paste", "<Control>V", "Paste entry from clipboard", lambda w,d: self.clip_paste(), 0, "<StockItem>", gtk.STOCK_PASTE), |
134 |
0f15e637f284
|
("/Edit/sep3", None, None, None, 0, "<Separator>"), |
135 |
0f15e637f284
|
("/Edit/_Find...", "<Control>F", "Search for an entry", lambda w,d: self.entry_find(), 0, "<StockItem>", gtk.STOCK_FIND), |
136 |
0f15e637f284
|
("/Edit/Find Ne_xt", "<Control>G", "Find the next search match", lambda w,d: self.__entry_find(self, revelation.data.SEARCH_NEXT), 0, "<Item>"), |
137 |
784a991e653d
|
("/Edit/Find Pre_vious", "<Shift><Control>G", "Find the previous search match", lambda w,d: self.__entry_find(self, revelation.data.SEARCH_PREV), 0, "<Item>"), |
138 |
0f15e637f284
|
("/Edit/sep4", None, None, None, 0, "<Separator>"), |
139 |
0f15e637f284
|
("/Edit/_Select All", "<Control>A", "Select all entries", lambda w,d: self.tree.select_all(), 0, "<Item>"), |
140 |
0f15e637f284
|
("/Edit/_Deselect All", "<Shift><Control>A", "Deselect all entries", lambda w,d: self.tree.unselect_all(), 0, "<Item>"), |
141 |
0f15e637f284
|
("/Edit/sep5", None, None, None, 0, "<Separator>"), |
142 |
9b3c9903350d
|
("/Edit/Prefere_nces", None, "Edit preferences", lambda w,d: revelation.dialog.Preferences(self, self.config).run(), 0, "<StockItem>", gtk.STOCK_PREFERENCES), |
143 |
0f15e637f284
|
|
144 |
0f15e637f284
|
("/_View", None, None, None, 0, "<Branch>"), |
145 |
9b3c9903350d
|
("/View/_Toolbar", None, "Toggle display of the toolbar", None, 0, "<CheckItem>"), |
146 |
9b3c9903350d
|
("/View/_Statusbar", None, "Toggle display of the statusbar", None, 0, "<CheckItem>"), |
147 |
0f15e637f284
|
("/View/sep1", None, None, None, 0, "<Separator>"), |
148 |
9b3c9903350d
|
("/View/Show _Passwords", "<Control>P", "Show passwords", None, 0, "<CheckItem>"), |
149 |
0f15e637f284
|
|
150 |
0f15e637f284
|
("/_Help", None, None, None, 0, "<Branch>"), |
151 |
0f15e637f284
|
("/Help/_Homepage", None, "Visit the Revelation homepage", lambda w,d: gnome.url_show(revelation.URL), 0, "<StockItem>", gtk.STOCK_HOME), |
152 |
0f15e637f284
|
("/Help/_About", None, "Show info about this application", lambda w,d: revelation.dialog.About(self).run(), 0, "<StockItem>", "gnome-stock-about") |
153 |
a877d43f0987
|
)) |
154 |
0f15e637f284
|
|
155 |
0f15e637f284
|
|
156 |
0f15e637f284
|
def __init_states(self): |
157 |
0f15e637f284
|
"Sets the initial application state" |
158 |
0f15e637f284
|
|
159 |
9b3c9903350d
|
self.set_default_size(self.config.get("view/window-width"), self.config.get("view/window-height")) |
160 |
f4e8220f0a3a
|
self.move(self.config.get("view/window-position-x"), self.config.get("view/window-position-y")) |
161 |
b181693cfdc7
|
self.connect("delete_event", lambda w,d: gtk.TRUE ^ self.quit()) |
162 |
b181693cfdc7
|
|
163 |
0f15e637f284
|
self.tree.select(None) |
164 |
0f15e637f284
|
self.dataview.display_info() |
165 |
5e73d779ae0d
|
self.data.set_file(None) |
166 |
0f15e637f284
|
|
167 |
0f15e637f284
|
self.if_menu.get_widget("<main>/Edit/Find Next").set_sensitive(gtk.FALSE) |
168 |
0f15e637f284
|
self.if_menu.get_widget("<main>/Edit/Find Previous").set_sensitive(gtk.FALSE) |
169 |
0f15e637f284
|
self.if_menu.get_widget("<main>/Edit/Undo").set_sensitive(gtk.FALSE) |
170 |
0f15e637f284
|
self.if_menu.get_widget("<main>/Edit/Redo").set_sensitive(gtk.FALSE) |
171 |
0f15e637f284
|
|
172 |
0f15e637f284
|
self.show_all() |
173 |
0f15e637f284
|
|
174 |
9b3c9903350d
|
self.config.bind_widget("view/passwords", self.if_menu.get_widget("<main>/View/Show Passwords")) |
175 |
9b3c9903350d
|
self.config.bind_widget("view/statusbar", self.if_menu.get_widget("<main>/View/Statusbar")) |
176 |
9b3c9903350d
|
self.config.bind_widget("view/toolbar", self.if_menu.get_widget("<main>/View/Toolbar")) |
177 |
0f15e637f284
|
|
178 |
9b3c9903350d
|
self.config.notify_add("view/statusbar", self.__cb_config_statusbar) |
179 |
9b3c9903350d
|
self.config.notify_add("view/toolbar", self.__cb_config_toolbar) |
180 |
0f15e637f284
|
|
181 |
0f15e637f284
|
|
182 |
0f15e637f284
|
def __init_toolbar(self): |
183 |
0f15e637f284
|
"Sets up the application toolbar" |
184 |
0f15e637f284
|
|
185 |
db7970bbbb93
|
self.toolbar.button_new = self.toolbar.append_stock(gtk.STOCK_NEW, "New file", lambda w,d: self.file_new()) |
186 |
db7970bbbb93
|
self.toolbar.button_open = self.toolbar.append_stock(gtk.STOCK_OPEN, "Open file", lambda w,d: self.file_open()) |
187 |
a877d43f0987
|
self.toolbar.button_save = self.toolbar.append_stock(gtk.STOCK_SAVE, "Save file", lambda w,d: self.file_save(self.data.file, self.data.password)) |
188 |
0f15e637f284
|
|
189 |
0f15e637f284
|
self.toolbar.append_space() |
190 |
0f15e637f284
|
|
191 |
db7970bbbb93
|
self.toolbar.button_entry_add = self.toolbar.append_stock(revelation.stock.STOCK_ADD, "Add a new entry", lambda w,d: self.entry_add()) |
192 |
db7970bbbb93
|
self.toolbar.button_entry_edit = self.toolbar.append_stock(revelation.stock.STOCK_EDIT, "Edit the selected entry", lambda w,d: self.entry_edit()) |
193 |
db7970bbbb93
|
self.toolbar.button_entry_remove = self.toolbar.append_stock(revelation.stock.STOCK_REMOVE, "Remove the selected entry", lambda w,d: self.entry_remove()) |
194 |
0f15e637f284
|
|
195 |
0f15e637f284
|
|
196 |
0f15e637f284
|
|
197 |
9b3c9903350d
|
# config callbacks |
198 |
9b3c9903350d
|
def __cb_config_statusbar(self, config, value, data): |
199 |
9b3c9903350d
|
"Config callback for statusbar changes" |
200 |
0f15e637f284
|
|
201 |
9b3c9903350d
|
if value == gtk.TRUE: |
202 |
0f15e637f284
|
self.statusbar.show() |
203 |
0f15e637f284
|
|
204 |
0f15e637f284
|
else: |
205 |
0f15e637f284
|
self.statusbar.hide() |
206 |
0f15e637f284
|
|
207 |
0f15e637f284
|
|
208 |
9b3c9903350d
|
def __cb_config_toolbar(self, config, value, data): |
209 |
9b3c9903350d
|
"Config callback for toolbar changes" |
210 |
0f15e637f284
|
|
211 |
9b3c9903350d
|
if value == gtk.TRUE: |
212 |
0f15e637f284
|
self.toolbar.show() |
213 |
0f15e637f284
|
|
214 |
0f15e637f284
|
else: |
215 |
0f15e637f284
|
self.toolbar.hide() |
216 |
0f15e637f284
|
|
217 |
0f15e637f284
|
|
218 |
0f15e637f284
|
|
219 |
0f15e637f284
|
# callbacks for handling ui states |
220 |
0f15e637f284
|
def __cb_state_clipboard(self, widget, data = None): |
221 |
0f15e637f284
|
"Sets clipboard item sensitivity as appropriate" |
222 |
0f15e637f284
|
|
223 |
0f15e637f284
|
self.if_menu.get_widget("<main>/Edit/Paste").set_sensitive(self.clipboard.has_contents()) |
224 |
0f15e637f284
|
|
225 |
0f15e637f284
|
|
226 |
0f15e637f284
|
def __cb_state_entry(self, widget, data = None): |
227 |
0f15e637f284
|
"Sets state for entry-dependent ui items" |
228 |
0f15e637f284
|
|
229 |
0f15e637f284
|
selcount = len(self.tree.get_selected()) |
230 |
0f15e637f284
|
|
231 |
0f15e637f284
|
self.toolbar.button_entry_add.set_sensitive(selcount < 2) |
232 |
0f15e637f284
|
self.if_menu.get_widget("<main>/Edit/Add Entry...").set_sensitive(selcount < 2) |
233 |
0f15e637f284
|
self.if_menu.get_widget("<main>/Edit/Paste").set_sensitive(selcount < 2 and self.clipboard.has_contents()) |
234 |
0f15e637f284
|
|
235 |
0f15e637f284
|
self.toolbar.button_entry_edit.set_sensitive(selcount == 1) |
236 |
0f15e637f284
|
self.if_menu.get_widget("<main>/Edit/Edit").set_sensitive(selcount == 1) |
237 |
0f15e637f284
|
|
238 |
0f15e637f284
|
self.toolbar.button_entry_remove.set_sensitive(selcount > 0) |
239 |
0f15e637f284
|
self.if_menu.get_widget("<main>/Edit/Remove").set_sensitive(selcount > 0) |
240 |
0f15e637f284
|
self.if_menu.get_widget("<main>/Edit/Cut").set_sensitive(selcount > 0) |
241 |
0f15e637f284
|
self.if_menu.get_widget("<main>/Edit/Copy").set_sensitive(selcount > 0) |
242 |
0f15e637f284
|
|
243 |
0f15e637f284
|
|
244 |
a877d43f0987
|
def __cb_state_file(self, widget, file = None): |
245 |
0f15e637f284
|
"Sets various states based on current file" |
246 |
0f15e637f284
|
|
247 |
a877d43f0987
|
self.if_menu.get_widget("<main>/File/Revert").set_sensitive(file is not None) |
248 |
a877d43f0987
|
self.if_menu.get_widget("<main>/File/Lock...").set_sensitive(file is not None) |
249 |
0f15e637f284
|
|
250 |
a877d43f0987
|
if file is None: |
251 |
0f15e637f284
|
self.set_title("[New file]") |
252 |
0f15e637f284
|
|
253 |
0f15e637f284
|
else: |
254 |
a877d43f0987
|
self.set_title(os.path.basename(file)) |
255 |
a877d43f0987
|
os.chdir(os.path.dirname(file)) |
256 |
0f15e637f284
|
|
257 |
0f15e637f284
|
|
258 |
0f15e637f284
|
def __cb_state_find(self, widget, data = None): |
259 |
0f15e637f284
|
"Sets ui item states for find-related items" |
260 |
0f15e637f284
|
|
261 |
0f15e637f284
|
self.if_menu.get_widget("<main>/Edit/Find Next").set_sensitive(self.finder.string != "") |
262 |
0f15e637f284
|
self.if_menu.get_widget("<main>/Edit/Find Previous").set_sensitive(self.finder.string != "") |
263 |
0f15e637f284
|
|
264 |
0f15e637f284
|
|
265 |
0f15e637f284
|
def __cb_state_undo(self, widget, data = None): |
266 |
0f15e637f284
|
"Sets states for undo-related ui items" |
267 |
0f15e637f284
|
|
268 |
0f15e637f284
|
# update undo widgets |
269 |
0f15e637f284
|
widget = self.if_menu.get_widget("<main>/Edit/Undo") |
270 |
0f15e637f284
|
action = "_Undo" |
271 |
0f15e637f284
|
|
272 |
0f15e637f284
|
if self.undoqueue.can_undo(): |
273 |
0f15e637f284
|
widget.get_children()[0].set_label(action + " " + self.undoqueue.get_action(revelation.data.UNDO).name) |
274 |
0f15e637f284
|
widget.set_sensitive(gtk.TRUE) |
275 |
0f15e637f284
|
|
276 |
0f15e637f284
|
else: |
277 |
0f15e637f284
|
widget.get_children()[0].set_label(action) |
278 |
0f15e637f284
|
widget.set_sensitive(gtk.FALSE) |
279 |
0f15e637f284
|
|
280 |
0f15e637f284
|
# update redo widgets |
281 |
0f15e637f284
|
widget = self.if_menu.get_widget("<main>/Edit/Redo") |
282 |
0f15e637f284
|
action = "_Redo" |
283 |
0f15e637f284
|
|
284 |
0f15e637f284
|
if self.undoqueue.can_redo(): |
285 |
0f15e637f284
|
widget.get_children()[0].set_label(action + " " + self.undoqueue.get_action(revelation.data.REDO).name) |
286 |
0f15e637f284
|
widget.set_sensitive(gtk.TRUE) |
287 |
0f15e637f284
|
|
288 |
0f15e637f284
|
else: |
289 |
0f15e637f284
|
widget.get_children()[0].set_label(action) |
290 |
0f15e637f284
|
widget.set_sensitive(gtk.FALSE) |
291 |
0f15e637f284
|
|
292 |
0f15e637f284
|
|
293 |
0f15e637f284
|
|
294 |
0f15e637f284
|
# other, normal callbacks |
295 |
b181693cfdc7
|
def __cb_popup_tree(self, widget, menuitems): |
296 |
b181693cfdc7
|
"Create a popup-menu for the treeview" |
297 |
0f15e637f284
|
|
298 |
0f15e637f284
|
# create the popup menu |
299 |
0f15e637f284
|
iters = self.tree.get_selected() |
300 |
b181693cfdc7
|
|
301 |
b181693cfdc7
|
if len(iters) == 0 or (len(iters) == 1 and self.data.get_entry(iters[0]).type == revelation.entry.ENTRY_FOLDER): |
302 |
b181693cfdc7
|
menuitems.append(("/_Add Entry...", None, "Create a new entry", lambda w,d: self.entry_add(), 0, "<StockItem>", revelation.stock.STOCK_ADD)) |
303 |
cea4127a11c0
|
|
304 |
cea4127a11c0
|
if len(iters) == 1: |
305 |
b181693cfdc7
|
menuitems.append(("/_Edit", None, "Edit the selected entry", lambda w,d: self.entry_edit(), 0, "<StockItem>", revelation.stock.STOCK_EDIT)) |
306 |
cea4127a11c0
|
|
307 |
cea4127a11c0
|
if len(iters) > 0: |
308 |
b181693cfdc7
|
menuitems.append(("/Re_move", None, "Remove the selected entry", lambda w,d: self.entry_remove(), 0, "<StockItem>", revelation.stock.STOCK_REMOVE)) |
309 |
cea4127a11c0
|
|
310 |
0f15e637f284
|
|
311 |
cea4127a11c0
|
clipboardmenu = [] |
312 |
cea4127a11c0
|
|
313 |
cea4127a11c0
|
if len(iters) > 0: |
314 |
b181693cfdc7
|
clipboardmenu.append(("/Cu_t", "", "Cut the selected entry to the clipboard", lambda w,d: self.clip_cut(), 0, "<StockItem>", gtk.STOCK_CUT)) |
315 |
b181693cfdc7
|
clipboardmenu.append(("/_Copy", "", "Copy the selected entry to the keyboard", lambda w,d: self.clip_copy(), 0, "<StockItem>", gtk.STOCK_COPY)) |
316 |
cea4127a11c0
|
|
317 |
cea4127a11c0
|
if len(iters) < 2 and self.clipboard.has_contents(): |
318 |
b181693cfdc7
|
clipboardmenu.append(("/_Paste", "", "Paste entry from clipboard", lambda w,d: self.clip_paste(), 0, "<StockItem>", gtk.STOCK_PASTE)) |
319 |
cea4127a11c0
|
|
320 |
0f15e637f284
|
|
321 |
cea4127a11c0
|
if len(clipboardmenu) > 0: |
322 |
cea4127a11c0
|
menuitems.append(("/sep1", None, None, None, 0, "<Separator>")) |
323 |
cea4127a11c0
|
menuitems.extend(clipboardmenu) |
324 |
cea4127a11c0
|
|
325 |
0f15e637f284
|
|
326 |
0f15e637f284
|
|
327 |
0f15e637f284
|
# various private methods |
328 |
cea4127a11c0
|
def __entry_find(self, parent, direction = revelation.data.SEARCH_NEXT): |
329 |
a877d43f0987
|
"Searches for an entry" |
330 |
a877d43f0987
|
|
331 |
9b3c9903350d
|
self.finder.folders = self.config.get("search/folders") |
332 |
9b3c9903350d
|
self.finder.casesens = self.config.get("search/casesens") |
333 |
9b3c9903350d
|
self.finder.namedesc = self.config.get("search/namedesc") |
334 |
cea4127a11c0
|
|
335 |
cea4127a11c0
|
match = self.finder.find(self.tree.get_active(), direction) |
336 |
cea4127a11c0
|
|
337 |
0f15e637f284
|
if match is None: |
338 |
cea4127a11c0
|
revelation.dialog.Error(parent, "No match found", "The string you searched for did not match any entries. Try using a different search-phrase.").run() |
339 |
a877d43f0987
|
|
340 |
cea4127a11c0
|
else: |
341 |
cea4127a11c0
|
self.tree.select(match) |
342 |
cea4127a11c0
|
|
343 |
cea4127a11c0
|
|
344 |
71831418a015
|
def __file_autosave(self): |
345 |
71831418a015
|
"Autosaves the current file, due to data modification" |
346 |
71831418a015
|
|
347 |
a877d43f0987
|
if self.data.file is None or self.data.password is None: |
348 |
71831418a015
|
return |
349 |
71831418a015
|
|
350 |
3794d9b38446
|
if not self.config.get("file/autosave"): |
351 |
71831418a015
|
return |
352 |
71831418a015
|
|
353 |
a877d43f0987
|
self.file_save(self.data.file, self.data.password) |
354 |
71831418a015
|
|
355 |
71831418a015
|
|
356 |
4ccca6b59faa
|
def __file_load(self, datafile): |
357 |
4ccca6b59faa
|
"Loads data from a file into an entrystore" |
358 |
4ccca6b59faa
|
|
359 |
4ccca6b59faa
|
try: |
360 |
4ccca6b59faa
|
if datafile.handler is None: |
361 |
4ccca6b59faa
|
datafile.detect_type() |
362 |
4ccca6b59faa
|
|
363 |
4ccca6b59faa
|
datafile.check_file() |
364 |
4ccca6b59faa
|
|
365 |
a877d43f0987
|
dialog = revelation.dialog.PasswordLoad(self, datafile.file) |
366 |
4ccca6b59faa
|
entrystore = None |
367 |
4ccca6b59faa
|
|
368 |
4ccca6b59faa
|
while 1: |
369 |
4ccca6b59faa
|
|
370 |
4ccca6b59faa
|
# load datafile, ask for password if needed |
371 |
4ccca6b59faa
|
try: |
372 |
4ccca6b59faa
|
if datafile.needs_password() and datafile.password is None: |
373 |
fe0f16515591
|
datafile.password = dialog.run() |
374 |
4ccca6b59faa
|
|
375 |
4ccca6b59faa
|
entrystore = datafile.load() |
376 |
4ccca6b59faa
|
|
377 |
4ccca6b59faa
|
except revelation.datahandler.PasswordError: |
378 |
4ccca6b59faa
|
datafile.password = None |
379 |
4ccca6b59faa
|
revelation.dialog.Error( |
380 |
4ccca6b59faa
|
self, "Incorrect password", |
381 |
4ccca6b59faa
|
"The password you entered for the file'" + datafile.file + "' was not correct." |
382 |
4ccca6b59faa
|
).run() |
383 |
4ccca6b59faa
|
|
384 |
4ccca6b59faa
|
except: |
385 |
4ccca6b59faa
|
dialog.destroy() |
386 |
4ccca6b59faa
|
raise |
387 |
4ccca6b59faa
|
|
388 |
4ccca6b59faa
|
else: |
389 |
4ccca6b59faa
|
dialog.destroy() |
390 |
4ccca6b59faa
|
break |
391 |
4ccca6b59faa
|
|
392 |
a78b3bc44c12
|
return entrystore |
393 |
a78b3bc44c12
|
|
394 |
4ccca6b59faa
|
except revelation.datahandler.FormatError: |
395 |
4ccca6b59faa
|
self.statusbar.set_status("Open failed") |
396 |
4ccca6b59faa
|
revelation.dialog.Error( |
397 |
4ccca6b59faa
|
self, "Invalid file format", |
398 |
784a991e653d
|
"The file '" + datafile.file + "' contains invalid data." |
399 |
4ccca6b59faa
|
).run() |
400 |
4ccca6b59faa
|
|
401 |
4ccca6b59faa
|
except revelation.entry.EntryError: |
402 |
4ccca6b59faa
|
self.statusbar.set_status("Open failed") |
403 |
4ccca6b59faa
|
revelation.dialog.Error( |
404 |
4ccca6b59faa
|
self, "Unknown data", |
405 |
784a991e653d
|
"The file '" + datafile.file + "' contains unknown data. It may have been created by a future version of Revelation, try upgrading to a newer version." |
406 |
4ccca6b59faa
|
).run() |
407 |
4ccca6b59faa
|
|
408 |
4ccca6b59faa
|
except revelation.datahandler.VersionError: |
409 |
4ccca6b59faa
|
self.statusbar.set_status("Open failed") |
410 |
4ccca6b59faa
|
revelation.dialog.Error( |
411 |
4ccca6b59faa
|
self, "Unknown data version", |
412 |
4ccca6b59faa
|
"The file '" + datafile.file + "' has a future version number - upgrade Revelation to a more recent version to open it." |
413 |
4ccca6b59faa
|
).run() |
414 |
4ccca6b59faa
|
|
415 |
4ccca6b59faa
|
except revelation.io.DetectError: |
416 |
4ccca6b59faa
|
self.statusbar.set_status("Open failed") |
417 |
4ccca6b59faa
|
revelation.dialog.Error( |
418 |
4ccca6b59faa
|
self, "Filetype autodetection failed", |
419 |
4ccca6b59faa
|
"The format of the file '" + datafile.file + "' could not be detected automatically. It may still be possible to open the file, try specifying the file type manually." |
420 |
4ccca6b59faa
|
).run() |
421 |
4ccca6b59faa
|
|
422 |
4ccca6b59faa
|
except IOError: |
423 |
4ccca6b59faa
|
self.statusbar.set_status("Open failed") |
424 |
4ccca6b59faa
|
revelation.dialog.Error( |
425 |
4ccca6b59faa
|
self, "Unable to open file", |
426 |
4ccca6b59faa
|
"The file '" + datafile.file + "' could not be opened. Make sure that the file exists, and that you have the proper permissions to open it." |
427 |
4ccca6b59faa
|
).run() |
428 |
4ccca6b59faa
|
|
429 |
4ccca6b59faa
|
except revelation.CancelError: |
430 |
4ccca6b59faa
|
dialog.destroy() |
431 |
b181693cfdc7
|
raise |
432 |
4ccca6b59faa
|
|
433 |
4ccca6b59faa
|
|
434 |
4ccca6b59faa
|
def __file_save(self, datafile): |
435 |
4ccca6b59faa
|
"Saves data to a file" |
436 |
4ccca6b59faa
|
|
437 |
4ccca6b59faa
|
try: |
438 |
a877d43f0987
|
if datafile.file != self.data.file and revelation.io.file_exists(datafile.file): |
439 |
4ccca6b59faa
|
revelation.dialog.FileOverwrite(self, datafile.file).run() |
440 |
4ccca6b59faa
|
|
441 |
4ccca6b59faa
|
if not datafile.needs_password(): |
442 |
4ccca6b59faa
|
revelation.dialog.FileExportInsecure(self).run() |
443 |
4ccca6b59faa
|
|
444 |
4ccca6b59faa
|
elif datafile.password is None: |
445 |
4ccca6b59faa
|
try: |
446 |
fe0f16515591
|
dialog = revelation.dialog.PasswordSave(self, datafile.file) |
447 |
fe0f16515591
|
datafile.password = dialog.run() |
448 |
4ccca6b59faa
|
dialog.destroy() |
449 |
4ccca6b59faa
|
|
450 |
4ccca6b59faa
|
except revelation.CancelError: |
451 |
4ccca6b59faa
|
dialog.destroy() |
452 |
4ccca6b59faa
|
raise |
453 |
4ccca6b59faa
|
|
454 |
4ccca6b59faa
|
|
455 |
4ccca6b59faa
|
datafile.save(self.data) |
456 |
4ccca6b59faa
|
|
457 |
a78b3bc44c12
|
return gtk.TRUE |
458 |
4ccca6b59faa
|
|
459 |
4ccca6b59faa
|
except IOError: |
460 |
4ccca6b59faa
|
revelation.dialog.Error(self, "Unable to write to file", "The file '" + datafile.file + "' could not be opened for writing. Make sure that you have the proper permissions to write to it.").run() |
461 |
4ccca6b59faa
|
self.statusbar.set_status("Save failed") |
462 |
a78b3bc44c12
|
|
463 |
4ccca6b59faa
|
return gtk.FALSE |
464 |
4ccca6b59faa
|
|
465 |
4ccca6b59faa
|
|
466 |
a877d43f0987
|
def __save_changes(self, dialog): |
467 |
a877d43f0987
|
"Asks the user if she wants to save her changes" |
468 |
a877d43f0987
|
|
469 |
a877d43f0987
|
try: |
470 |
a877d43f0987
|
if not self.data.changed: |
471 |
a877d43f0987
|
return gtk.TRUE |
472 |
a877d43f0987
|
|
473 |
a877d43f0987
|
if dialog(self).run() == gtk.TRUE: |
474 |
a877d43f0987
|
return self.file_save(self.data.file, self.data.password) |
475 |
a877d43f0987
|
|
476 |
a78b3bc44c12
|
return gtk.TRUE |
477 |
a78b3bc44c12
|
|
478 |
a877d43f0987
|
except revelation.CancelError: |
479 |
a877d43f0987
|
return gtk.FALSE |
480 |
a877d43f0987
|
|
481 |
a877d43f0987
|
|
482 |
4ccca6b59faa
|
|
483 |
0f15e637f284
|
# public methods |
484 |
cea4127a11c0
|
def change_password(self): |
485 |
3794d9b38446
|
"Changes the password of the current data file" |
486 |
3794d9b38446
|
|
487 |
cea4127a11c0
|
try: |
488 |
b181693cfdc7
|
dialog = revelation.dialog.PasswordChange(self, self.data.password) |
489 |
b181693cfdc7
|
self.data.password = dialog.run() |
490 |
cea4127a11c0
|
|
491 |
fe0f16515591
|
self.__file_autosave() |
492 |
fe0f16515591
|
self.statusbar.set_status("Password changed") |
493 |
cea4127a11c0
|
|
494 |
cea4127a11c0
|
except revelation.CancelError: |
495 |
cea4127a11c0
|
self.statusbar.set_status("Password change cancelled") |
496 |
cea4127a11c0
|
|
497 |
cea4127a11c0
|
dialog.destroy() |
498 |
cea4127a11c0
|
|
499 |
cea4127a11c0
|
|
500 |
cea4127a11c0
|
def clip_copy(self): |
501 |
3794d9b38446
|
"Copies selected entries to the clipboard" |
502 |
3794d9b38446
|
|
503 |
cea4127a11c0
|
iters = self.data.filter_parents(self.tree.get_selected()) |
504 |
cea4127a11c0
|
self.clipboard.copy(self.data, iters) |
505 |
cea4127a11c0
|
|
506 |
cea4127a11c0
|
|
507 |
cea4127a11c0
|
def clip_cut(self): |
508 |
3794d9b38446
|
"Cuts selected entries to the clipboard" |
509 |
3794d9b38446
|
|
510 |
cea4127a11c0
|
iters = self.data.filter_parents(self.tree.get_selected()) |
511 |
268984dc47cf
|
self.undoqueue.add_action(revelation.data.UNDO_ACTION_CUT, iters) |
512 |
cea4127a11c0
|
self.clipboard.cut(self.data, iters) |
513 |
b181693cfdc7
|
self.__file_autosave() |
514 |
cea4127a11c0
|
self.tree.unselect_all() |
515 |
cea4127a11c0
|
|
516 |
cea4127a11c0
|
|
517 |
cea4127a11c0
|
def clip_paste(self): |
518 |
3794d9b38446
|
"Pastes entries from the clipboard" |
519 |
3794d9b38446
|
|
520 |
4787d15f40a4
|
if not self.clipboard.has_contents(): |
521 |
cea4127a11c0
|
return |
522 |
cea4127a11c0
|
|
523 |
4787d15f40a4
|
iters = self.clipboard.paste(self.data, self.tree.get_active()) |
524 |
268984dc47cf
|
self.undoqueue.add_action(revelation.data.UNDO_ACTION_PASTE, iters) |
525 |
b181693cfdc7
|
self.__file_autosave() |
526 |
cea4127a11c0
|
self.tree.select(iters[0]) |
527 |
cea4127a11c0
|
|
528 |
cea4127a11c0
|
|
529 |
cea4127a11c0
|
def entry_add(self): |
530 |
3794d9b38446
|
"Adds an entry" |
531 |
3794d9b38446
|
|
532 |
cea4127a11c0
|
try: |
533 |
f54fce826711
|
entry = revelation.dialog.EntryEdit(self, "Add entry").run() |
534 |
dc936312d815
|
iter = self.data.add_entry(self.tree.get_active(), entry) |
535 |
71831418a015
|
|
536 |
268984dc47cf
|
self.undoqueue.add_action(revelation.data.UNDO_ACTION_ADD, iter) |
537 |
71831418a015
|
self.__file_autosave() |
538 |
b181693cfdc7
|
|
539 |
cea4127a11c0
|
self.tree.select(iter) |
540 |
dc936312d815
|
self.statusbar.set_status("Added entry '" + entry.name + "'") |
541 |
cea4127a11c0
|
|
542 |
cea4127a11c0
|
except revelation.CancelError: |
543 |
cea4127a11c0
|
self.statusbar.set_status("Add entry cancelled") |
544 |
cea4127a11c0
|
|
545 |
cea4127a11c0
|
|
546 |
cea4127a11c0
|
def entry_edit(self): |
547 |
3794d9b38446
|
"Edits an entry" |
548 |
3794d9b38446
|
|
549 |
cea4127a11c0
|
iter = self.tree.get_active() |
550 |
cea4127a11c0
|
|
551 |
0f15e637f284
|
if iter is None: |
552 |
cea4127a11c0
|
return |
553 |
cea4127a11c0
|
|
554 |
cea4127a11c0
|
try: |
555 |
dc936312d815
|
entry = self.data.get_entry(iter) |
556 |
f54fce826711
|
dialog = revelation.dialog.EntryEdit(self, "Edit entry", entry) |
557 |
cea4127a11c0
|
|
558 |
dc936312d815
|
if entry.type == revelation.entry.ENTRY_FOLDER and self.data.iter_n_children(iter) > 0: |
559 |
cea4127a11c0
|
dialog.set_typechange_allowed(gtk.FALSE) |
560 |
cea4127a11c0
|
|
561 |
dc936312d815
|
newentry = dialog.run() |
562 |
dc936312d815
|
self.data.update_entry(iter, newentry) |
563 |
268984dc47cf
|
self.undoqueue.add_action(revelation.data.UNDO_ACTION_EDIT, iter, entry) |
564 |
b181693cfdc7
|
|
565 |
71831418a015
|
self.__file_autosave() |
566 |
cea4127a11c0
|
self.tree.select(iter) |
567 |
dc936312d815
|
self.statusbar.set_status("Updated entry '" + newentry.name + "'") |
568 |
cea4127a11c0
|
|
569 |
cea4127a11c0
|
except revelation.CancelError: |
570 |
cea4127a11c0
|
self.statusbar.set_status("Update entry cancelled") |
571 |
cea4127a11c0
|
|
572 |
cea4127a11c0
|
|
573 |
cea4127a11c0
|
def entry_find(self): |
574 |
3794d9b38446
|
"Searches for an entry" |
575 |
3794d9b38446
|
|
576 |
9b3c9903350d
|
dialog = revelation.dialog.Find(self, self.config) |
577 |
cea4127a11c0
|
dialog.entry_phrase.set_text(self.finder.string) |
578 |
cea4127a11c0
|
dialog.dropdown.set_type(self.finder.type) |
579 |
cea4127a11c0
|
|
580 |
cea4127a11c0
|
while 1: |
581 |
cea4127a11c0
|
response = dialog.run() |
582 |
cea4127a11c0
|
self.finder.string = dialog.entry_phrase.get_text() |
583 |
cea4127a11c0
|
self.finder.type = dialog.dropdown.get_type() |
584 |
cea4127a11c0
|
|
585 |
cea4127a11c0
|
if response == revelation.dialog.RESPONSE_NEXT: |
586 |
cea4127a11c0
|
self.__entry_find(dialog, revelation.data.SEARCH_NEXT) |
587 |
cea4127a11c0
|
|
588 |
cea4127a11c0
|
elif response == revelation.dialog.RESPONSE_PREVIOUS: |
589 |
cea4127a11c0
|
self.__entry_find(dialog, revelation.data.SEARCH_PREV) |
590 |
cea4127a11c0
|
|
591 |
cea4127a11c0
|
else: |
592 |
cea4127a11c0
|
dialog.destroy() |
593 |
cea4127a11c0
|
break |
594 |
cea4127a11c0
|
|
595 |
cea4127a11c0
|
|
596 |
cea4127a11c0
|
def entry_remove(self): |
597 |
3794d9b38446
|
"Removes one or more entries" |
598 |
3794d9b38446
|
|
599 |
cea4127a11c0
|
iters = self.tree.get_selected() |
600 |
cea4127a11c0
|
|
601 |
cea4127a11c0
|
if len(iters) == 0: |
602 |
cea4127a11c0
|
return |
603 |
cea4127a11c0
|
|
604 |
a877d43f0987
|
entries = self.data.get_entries(iters) |
605 |
cea4127a11c0
|
|
606 |
f54fce826711
|
|
607 |
a877d43f0987
|
try: |
608 |
a877d43f0987
|
if revelation.dialog.EntryRemove(self, entries).run() != gtk.TRUE: |
609 |
a877d43f0987
|
raise revelation.CancelError |
610 |
f54fce826711
|
|
611 |
f54fce826711
|
if len(iters) == 1: |
612 |
f54fce826711
|
statustext = "Removed entry '" + entries[0].name + "'" |
613 |
cea4127a11c0
|
|
614 |
cea4127a11c0
|
else: |
615 |
f54fce826711
|
statustext = "Removed " + str(len(entries)) + " entries" |
616 |
cea4127a11c0
|
|
617 |
cea4127a11c0
|
iters = self.data.filter_parents(iters) |
618 |
268984dc47cf
|
self.undoqueue.add_action(revelation.data.UNDO_ACTION_REMOVE, iters) |
619 |
cea4127a11c0
|
|
620 |
cea4127a11c0
|
for iter in iters: |
621 |
cea4127a11c0
|
self.data.remove_entry(iter) |
622 |
cea4127a11c0
|
|
623 |
71831418a015
|
self.__file_autosave() |
624 |
cea4127a11c0
|
self.tree.unselect_all() |
625 |
cea4127a11c0
|
self.statusbar.set_status(statustext) |
626 |
cea4127a11c0
|
|
627 |
a877d43f0987
|
except revelation.CancelError: |
628 |
cea4127a11c0
|
self.statusbar.set_status("Remove entry cancelled") |
629 |
cea4127a11c0
|
|
630 |
cea4127a11c0
|
|
631 |
f54fce826711
|
|
632 |
cea4127a11c0
|
def file_export(self): |
633 |
4ccca6b59faa
|
"Exports data to a foreign file format" |
634 |
4ccca6b59faa
|
|
635 |
cea4127a11c0
|
try: |
636 |
4ccca6b59faa
|
file, handler = revelation.dialog.ExportFileSelector(self).run() |
637 |
4ccca6b59faa
|
datafile = revelation.io.DataFile(file, handler) |
638 |
4ccca6b59faa
|
self.__file_save(datafile) |
639 |
a78b3bc44c12
|
self.statusbar.set_status("Data exported to " + datafile.file) |
640 |
cea4127a11c0
|
|
641 |
cea4127a11c0
|
except revelation.CancelError: |
642 |
cea4127a11c0
|
self.statusbar.set_status("Export cancelled") |
643 |
cea4127a11c0
|
|
644 |
cea4127a11c0
|
|
645 |
4ccca6b59faa
|
def file_import(self): |
646 |
4ccca6b59faa
|
"Imports data from a foreign file" |
647 |
cea4127a11c0
|
|
648 |
cea4127a11c0
|
try: |
649 |
4ccca6b59faa
|
file, handler = revelation.dialog.ImportFileSelector(self).run() |
650 |
4ccca6b59faa
|
datafile = revelation.io.DataFile(file, handler) |
651 |
4ccca6b59faa
|
entrystore = self.__file_load(datafile) |
652 |
cea4127a11c0
|
|
653 |
4ccca6b59faa
|
if entrystore is None: |
654 |
4ccca6b59faa
|
return |
655 |
cea4127a11c0
|
|
656 |
cea4127a11c0
|
iters = self.data.import_entrystore(entrystore) |
657 |
268984dc47cf
|
self.undoqueue.add_action(revelation.data.UNDO_ACTION_IMPORT, iters) |
658 |
71831418a015
|
self.__file_autosave() |
659 |
cea4127a11c0
|
self.statusbar.set_status("Data imported from " + datafile.file) |
660 |
cea4127a11c0
|
|
661 |
a78b3bc44c12
|
except revelation.CancelError: |
662 |
a78b3bc44c12
|
self.statusbar.set_status("Import cancelled") |
663 |
a78b3bc44c12
|
|
664 |
cea4127a11c0
|
|
665 |
cea4127a11c0
|
def file_lock(self): |
666 |
4ccca6b59faa
|
"Locks the current data file" |
667 |
4ccca6b59faa
|
|
668 |
b181693cfdc7
|
if self.data.password is None: |
669 |
cea4127a11c0
|
return |
670 |
cea4127a11c0
|
|
671 |
cea4127a11c0
|
iter = self.tree.get_active() |
672 |
cea4127a11c0
|
self.tree.set_model(None) |
673 |
cea4127a11c0
|
self.dataview.clear() |
674 |
cea4127a11c0
|
self.statusbar.set_status("File locked") |
675 |
cea4127a11c0
|
|
676 |
fe0f16515591
|
dialog = revelation.dialog.PasswordLock(self) |
677 |
cea4127a11c0
|
|
678 |
cea4127a11c0
|
while 1: |
679 |
b181693cfdc7
|
if dialog.run() == self.data.password: |
680 |
fe0f16515591
|
break |
681 |
cea4127a11c0
|
|
682 |
fe0f16515591
|
else: |
683 |
fe0f16515591
|
revelation.dialog.Error( |
684 |
fe0f16515591
|
dialog, "Incorrect password", |
685 |
fe0f16515591
|
"The password you entered was not correct, please try again." |
686 |
fe0f16515591
|
).run() |
687 |
4ccca6b59faa
|
|
688 |
cea4127a11c0
|
|
689 |
cea4127a11c0
|
dialog.destroy() |
690 |
cea4127a11c0
|
|
691 |
cea4127a11c0
|
self.tree.set_model(self.data) |
692 |
cea4127a11c0
|
self.tree.select(iter) |
693 |
4ccca6b59faa
|
self.statusbar.set_status("File unlocked") |
694 |
cea4127a11c0
|
|
695 |
cea4127a11c0
|
|
696 |
cea4127a11c0
|
def file_new(self): |
697 |
4ccca6b59faa
|
"Opens a new file" |
698 |
4ccca6b59faa
|
|
699 |
a877d43f0987
|
if not self.__save_changes(revelation.dialog.FileChangedNew): |
700 |
cea4127a11c0
|
self.statusbar.set_status("New file cancelled") |
701 |
4ccca6b59faa
|
return |
702 |
cea4127a11c0
|
|
703 |
cea4127a11c0
|
self.data.clear() |
704 |
cea4127a11c0
|
self.statusbar.set_status("New file created") |
705 |
cea4127a11c0
|
|
706 |
cea4127a11c0
|
|
707 |
4ccca6b59faa
|
def file_open(self, file = None, password = None): |
708 |
4ccca6b59faa
|
"Opens a data file" |
709 |
cea4127a11c0
|
|
710 |
cea4127a11c0
|
try: |
711 |
a877d43f0987
|
if not self.__save_changes(revelation.dialog.FileChangedOpen): |
712 |
a877d43f0987
|
raise revelation.CancelError |
713 |
cea4127a11c0
|
|
714 |
4ccca6b59faa
|
if file is None: |
715 |
b33428fed2ea
|
file = revelation.dialog.FileSelector(self, "Select file to open").run() |
716 |
cea4127a11c0
|
|
717 |
4ccca6b59faa
|
datafile = revelation.io.DataFile(file, revelation.datahandler.Revelation, password) |
718 |
4ccca6b59faa
|
entrystore = self.__file_load(datafile) |
719 |
cea4127a11c0
|
|
720 |
4ccca6b59faa
|
if entrystore is None: |
721 |
4ccca6b59faa
|
return |
722 |
cea4127a11c0
|
|
723 |
a78b3bc44c12
|
self.data.replace_entrystore(entrystore) |
724 |
a78b3bc44c12
|
self.statusbar.set_status("Opened file " + datafile.file) |
725 |
a78b3bc44c12
|
|
726 |
a78b3bc44c12
|
|
727 |
cea4127a11c0
|
except revelation.CancelError: |
728 |
cea4127a11c0
|
self.statusbar.set_status("Open cancelled") |
729 |
cea4127a11c0
|
|
730 |
cea4127a11c0
|
|
731 |
cea4127a11c0
|
def file_revert(self): |
732 |
4ccca6b59faa
|
"Reverts to the saved version of the file" |
733 |
4ccca6b59faa
|
|
734 |
a877d43f0987
|
if not self.__save_changes(revelation.dialog.FileChangedRevert): |
735 |
f54fce826711
|
self.statusbar.set_status("Revert cancelled") |
736 |
cea4127a11c0
|
return gtk.FALSE |
737 |
cea4127a11c0
|
|
738 |
f54fce826711
|
self.data.changed = gtk.FALSE |
739 |
a877d43f0987
|
self.file_open(self.data.file, self.data.filepassword) |
740 |
cea4127a11c0
|
|
741 |
cea4127a11c0
|
|
742 |
cea4127a11c0
|
def file_save(self, file = None, password = None): |
743 |
4ccca6b59faa
|
"Saves a data file" |
744 |
4ccca6b59faa
|
|
745 |
cea4127a11c0
|
try: |
746 |
4ccca6b59faa
|
if file is None: |
747 |
b33428fed2ea
|
file = revelation.dialog.FileSelector(self, "Select file to save data to").run() |
748 |
cea4127a11c0
|
|
749 |
4ccca6b59faa
|
datafile = revelation.io.DataFile(file, revelation.datahandler.Revelation, password) |
750 |
cea4127a11c0
|
|
751 |
4ccca6b59faa
|
if self.__file_save(datafile) == gtk.TRUE: |
752 |
b181693cfdc7
|
self.data.set_file(file, password) |
753 |
4ccca6b59faa
|
self.statusbar.set_status("Data saved to file " + file) |
754 |
a877d43f0987
|
|
755 |
4ccca6b59faa
|
return gtk.TRUE |
756 |
cea4127a11c0
|
|
757 |
cea4127a11c0
|
except revelation.CancelError: |
758 |
cea4127a11c0
|
self.statusbar.set_status("Save cancelled") |
759 |
cea4127a11c0
|
return gtk.FALSE |
760 |
cea4127a11c0
|
|
761 |
cea4127a11c0
|
|
762 |
cea4127a11c0
|
def quit(self): |
763 |
3794d9b38446
|
"Quits the application" |
764 |
3794d9b38446
|
|
765 |
a877d43f0987
|
if not self.__save_changes(revelation.dialog.FileChangedQuit): |
766 |
cea4127a11c0
|
self.statusbar.set_status("Quit cancelled") |
767 |
cea4127a11c0
|
return gtk.FALSE |
768 |
cea4127a11c0
|
|
769 |
1aa324cfd765
|
width, height = self.get_size() |
770 |
9b3c9903350d
|
self.config.set("view/window-width", width) |
771 |
9b3c9903350d
|
self.config.set("view/window-height", height) |
772 |
f4e8220f0a3a
|
|
773 |
f4e8220f0a3a
|
x, y = self.get_position() |
774 |
f4e8220f0a3a
|
self.config.set("view/window-position-x", x) |
775 |
f4e8220f0a3a
|
self.config.set("view/window-position-y", y) |
776 |
f4e8220f0a3a
|
|
777 |
9b3c9903350d
|
self.config.set("view/pane-position", self.hpaned.get_position()) |
778 |
1aa324cfd765
|
|
779 |
cea4127a11c0
|
gtk.mainquit() |
780 |
cea4127a11c0
|
return gtk.TRUE |
781 |
cea4127a11c0
|
|
782 |
cea4127a11c0
|
|
783 |
268984dc47cf
|
def redo(self): |
784 |
268984dc47cf
|
"Redo the previously undone operation" |
785 |
268984dc47cf
|
|
786 |
268984dc47cf
|
if not self.undoqueue.can_redo(): |
787 |
268984dc47cf
|
return |
788 |
268984dc47cf
|
|
789 |
268984dc47cf
|
action = self.undoqueue.get_action(revelation.data.REDO) |
790 |
268984dc47cf
|
iters = self.undoqueue.redo() |
791 |
268984dc47cf
|
|
792 |
268984dc47cf
|
if len(iters) > 0: |
793 |
268984dc47cf
|
self.tree.select(iters[0]) |
794 |
b181693cfdc7
|
|
795 |
268984dc47cf
|
else: |
796 |
268984dc47cf
|
self.tree.unselect_all() |
797 |
268984dc47cf
|
|
798 |
b181693cfdc7
|
self.__file_autosave() |
799 |
268984dc47cf
|
self.statusbar.set_status(action.name.capitalize() + " redone") |
800 |
268984dc47cf
|
|
801 |
268984dc47cf
|
|
802 |
b181693cfdc7
|
def run(self): |
803 |
3794d9b38446
|
"Run the application" |
804 |
3794d9b38446
|
|
805 |
b181693cfdc7
|
if len(sys.argv) > 1: |
806 |
b181693cfdc7
|
self.file_open(os.path.abspath(sys.argv[1])) |
807 |
a877d43f0987
|
|
808 |
a877d43f0987
|
elif self.config.get("file/autoload") and self.config.get("file/autoload_file") != "": |
809 |
9b3c9903350d
|
self.file_open(self.config.get("file/autoload_file")) |
810 |
cea4127a11c0
|
|
811 |
cea4127a11c0
|
gtk.main() |
812 |
cea4127a11c0
|
|
813 |
cea4127a11c0
|
|
814 |
268984dc47cf
|
def undo(self): |
815 |
268984dc47cf
|
"Attempts to undo the previous operation" |
816 |
cea4127a11c0
|
|
817 |
268984dc47cf
|
if not self.undoqueue.can_undo(): |
818 |
268984dc47cf
|
return |
819 |
cea4127a11c0
|
|
820 |
268984dc47cf
|
action = self.undoqueue.get_action() |
821 |
268984dc47cf
|
iters = self.undoqueue.undo() |
822 |
cea4127a11c0
|
|
823 |
cea4127a11c0
|
if len(iters) > 0: |
824 |
cea4127a11c0
|
self.tree.select(iters[0]) |
825 |
b181693cfdc7
|
|
826 |
cea4127a11c0
|
else: |
827 |
cea4127a11c0
|
self.tree.unselect_all() |
828 |
cea4127a11c0
|
|
829 |
b181693cfdc7
|
self.__file_autosave() |
830 |
268984dc47cf
|
self.statusbar.set_status(action.name.capitalize() + " undone") |
831 |
cea4127a11c0
|
|
832 |
cea4127a11c0
|
|
833 |
cea4127a11c0
|
|
834 |
cea4127a11c0
|
if __name__ == "__main__": |
835 |
b181693cfdc7
|
Revelation().run() |
836 |
cea4127a11c0
|