1 """
2 Draws the applications main window
3
4 Also manages the callbacks from menu and GUI items
5
6 Copyright: John Stowers, 2006
7 License: GPLv2
8 """
9 import gobject
10 import gtk, gtk.glade
11 import gnome.ui
12 import os.path
13 import gettext
14 import threading
15 from gettext import gettext as _
16 import logging
17 log = logging.getLogger("gtkui.UI")
18
19 import conduit
20 import conduit.Web as Web
21 import conduit.Conduit as Conduit
22 import conduit.gtkui.Canvas as Canvas
23 import conduit.gtkui.MsgArea as MsgArea
24 import conduit.gtkui.Tree as Tree
25 import conduit.gtkui.ConflictResolver as ConflictResolver
26 import conduit.gtkui.Database as Database
27
28
29 DEFAULT_CONDUIT_BROWSER = "gtkmozembed"
30 DEVELOPER_WEB_LINKS = (
31
32 ("Introduction", "http://www.conduit-project.org/wiki/Development"),
33 ("Writing a Data Provider", "http://www.conduit-project.org/wiki/WritingADataProvider"),
34 ("API Documentation", "http://doc.conduit-project.org/conduit/"),
35 ("Test Results", "http://tests.conduit-project.org/")
36 )
37
38
39 for module in gtk.glade, gettext:
40 module.bindtextdomain('conduit', conduit.LOCALE_DIR)
41 module.textdomain('conduit')
42
44 """
45 The main conduit window.
46 """
47 - def __init__(self, conduitApplication, moduleManager, typeConverter, syncManager):
48 """
49 Constructs the mainwindow. Throws up a splash screen to cover
50 the most time consuming pieces
51 """
52 gnome.ui.authentication_manager_init()
53
54 self.conduitApplication = conduitApplication
55
56
57
58 icon_dirs = [
59 conduit.SHARED_DATA_DIR,
60 conduit.SHARED_MODULE_DIR,
61 os.path.join(conduit.SHARED_DATA_DIR,"icons"),
62 os.path.join(conduit.USER_DIR, "modules")
63 ]
64 for i in icon_dirs:
65 gtk.icon_theme_get_default().prepend_search_path(i)
66
67 self.gladeFile = os.path.join(conduit.SHARED_DATA_DIR, "conduit.glade")
68 self.widgets = gtk.glade.XML(self.gladeFile, "MainWindow")
69
70 dic = { "on_mainwindow_delete" : self.on_window_closed,
71 "on_mainwindow_state_event" : self.on_window_state_event,
72 "on_synchronize_activate" : self.on_synchronize_all_clicked,
73 "on_cancel_activate" : self.on_cancel_all_clicked,
74 "on_quit_activate" : self.on_window_closed,
75 "on_clear_canvas_activate" : self.on_clear_canvas,
76 "on_preferences_activate" : self.on_conduit_preferences,
77 "on_about_activate" : self.on_about_conduit,
78 "on_contents_activate" : self.on_help,
79 "on_save1_activate" : self.save_settings,
80 None : None
81 }
82 self.widgets.signal_autoconnect(dic)
83
84
85 self.type_converter = typeConverter
86 self.sync_manager = syncManager
87
88
89 self.mainWindow = self.widgets.get_widget("MainWindow")
90
91 if conduit.GLOBALS.settings.get("gui_use_rgba_colormap") == True:
92 screen = self.mainWindow.get_screen()
93 colormap = screen.get_rgba_colormap()
94 if colormap:
95 gtk.widget_set_default_colormap(colormap)
96 self.mainWindow.set_position(gtk.WIN_POS_CENTER)
97 self.mainWindow.set_icon_name("conduit")
98 title = "Conduit"
99 if conduit.IS_DEVELOPMENT_VERSION:
100 title = title + " - %s (Development Version)" % conduit.VERSION
101 if not conduit.IS_INSTALLED:
102 title = title + " - Running Uninstalled"
103 self.mainWindow.set_title(title)
104
105
106 self.canvasSW = self.widgets.get_widget("canvasScrolledWindow")
107 self.hpane = self.widgets.get_widget("hpaned1")
108
109
110 msg = MsgArea.MsgAreaController()
111 self.widgets.get_widget("mainVbox").pack_start(msg, False, False)
112 self.canvas = Canvas.Canvas(
113 parentWindow=self.mainWindow,
114 typeConverter=self.type_converter,
115 syncManager=self.sync_manager,
116 dataproviderMenu=gtk.glade.XML(self.gladeFile, "DataProviderMenu"),
117 conduitMenu=gtk.glade.XML(self.gladeFile, "ConduitMenu"),
118 msg=msg
119 )
120 self.canvasSW.add(self.canvas)
121 self.canvas.connect('drag-drop', self.drop_cb)
122 self.canvas.connect("drag-data-received", self.drag_data_received_data)
123
124
125 self.dataproviderTreeModel = Tree.DataProviderTreeModel()
126 dataproviderScrolledWindow = self.widgets.get_widget("scrolledwindow2")
127 self.dataproviderTreeView = Tree.DataProviderTreeView(self.dataproviderTreeModel)
128 dataproviderScrolledWindow.add(self.dataproviderTreeView)
129
130
131 self.conflictResolver = ConflictResolver.ConflictResolver(self.widgets)
132
133
134 self.cancelSyncButton = self.widgets.get_widget('cancel')
135 self.hpane.set_position(conduit.GLOBALS.settings.get("gui_hpane_postion"))
136 self.dataproviderTreeView.set_expand_rows()
137 self.window_state = 0
138
139
140
141 if conduit.IS_DEVELOPMENT_VERSION:
142 helpMenu = self.widgets.get_widget("help_menu")
143 developersMenuItem = gtk.ImageMenuItem("Developers")
144 developersMenuItem.set_image(
145 gtk.image_new_from_icon_name(
146 "applications-development",
147 gtk.ICON_SIZE_MENU))
148 developersMenu = gtk.Menu()
149 developersMenuItem.set_submenu(developersMenu)
150 helpMenu.prepend(developersMenuItem)
151 for name,url in DEVELOPER_WEB_LINKS:
152 item = gtk.ImageMenuItem(name)
153 item.set_image(
154 gtk.image_new_from_icon_name(
155 "applications-internet",
156 gtk.ICON_SIZE_MENU))
157 item.connect("activate",self.on_developer_menu_item_clicked,name,url)
158 developersMenu.append(item)
159
160
161 - def on_developer_menu_item_clicked(self, menuitem, name, url):
162 threading.Thread(
163 target=Web.LoginMagic,
164 args=(name, url),
165 kwargs={"login_function":lambda: True}
166 ).start()
167
168 - def on_conduit_added(self, syncset, cond):
169 cond.connect("sync-started", self.on_sync_started)
170 cond.connect("sync-completed", self.on_sync_completed)
171 cond.connect("sync-conflict", self.conflictResolver.on_conflict)
172
173 - def set_model(self, syncSet):
174 self.syncSet = syncSet
175 self.syncSet.connect("conduit-added", self.on_conduit_added)
176 self.canvas.set_sync_set(syncSet)
177
179 """
180 Present the main window. Enjoy your window
181 """
182 log.debug("Presenting GUI")
183 self.mainWindow.show_all()
184 self.mainWindow.present()
185
187 """
188 Iconifies the main window
189 """
190 log.debug("Iconifying GUI")
191 self.mainWindow.hide()
192
193 - def is_visible(self):
194 """
195 Returns True if mainWindow is visible
196 (not minimized or withdrawn)
197 """
198 minimized = self.window_state & gtk.gdk.WINDOW_STATE_ICONIFIED
199 return (not minimized) and self.mainWindow.get_property('visible')
200
201 - def on_sync_started(self, thread):
202 self.cancelSyncButton.set_property("sensitive", True)
203
204 - def on_sync_completed(self, thread, aborted, error, conflict):
205 self.cancelSyncButton.set_property(
206 "sensitive",
207 conduit.GLOBALS.syncManager.is_busy()
208 )
209
211 """
212 Synchronize all valid conduits on the canvas
213 """
214 self.conduitApplication.Synchronize()
215
216 - def on_cancel_all_clicked(self, widget):
217 """
218 Cancels all currently runnings syncs
219 """
220 self.conduitApplication.Cancel()
221
222 - def on_clear_canvas(self, widget):
223 """
224 Clear the canvas and start a new sync set
225 """
226 self.canvas.clear_canvas()
227
228 - def on_conduit_preferences(self, widget):
229 """
230 Show the properties of the current sync set (status, conflicts, etc
231 Edit the sync specific properties
232 """
233 def on_clear_button_clicked(sender, treeview, sqliteListStore):
234 treeview.set_model(None)
235 conduit.GLOBALS.mappingDB.delete()
236 treeview.set_model(sqliteListStore)
237
238
239 CONVERT_FROM_MESSAGE = _("Convert from")
240 CONVERT_INTO_MESSAGE = _("into")
241
242 convertables = self.type_converter.get_convertables_list()
243 converterListStore = gtk.ListStore( str )
244 for froms,tos in convertables:
245 string = "%s %s %s %s" % (CONVERT_FROM_MESSAGE, froms, CONVERT_INTO_MESSAGE, tos)
246 converterListStore.append( (string,) )
247 dataProviderListStore = gtk.ListStore( str, bool )
248
249 for i in conduit.GLOBALS.moduleManager.get_modules_by_type("sink","source","twoway"):
250 dataProviderListStore.append(("Name: %s\nDescription: %s)" % (i.name, i.description), True))
251
252 for f in conduit.GLOBALS.moduleManager.invalidFiles:
253 dataProviderListStore.append(("Error loading file: %s" % f, False))
254
255
256 tree = gtk.glade.XML(self.gladeFile, "PreferencesDialog")
257 notebook = tree.get_widget("prop_notebook")
258
259
260 if conduit.IS_DEVELOPMENT_VERSION:
261 vbox = gtk.VBox(False,5)
262
263
264
265 treeview = gtk.TreeView()
266 treeview.set_headers_visible(True)
267 treeview.set_fixed_height_mode(True)
268 index = 1
269 db = conduit.GLOBALS.mappingDB._db
270 for name in db.get_fields("mappings"):
271 column = gtk.TreeViewColumn(
272 name,
273 gtk.CellRendererText(),
274 text=index)
275 column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
276 column.set_fixed_width(250)
277 treeview.append_column(column)
278 index = index + 1
279
280 store = Database.GenericDBListStore("mappings", db)
281 treeview.set_model(store)
282
283 sw = gtk.ScrolledWindow()
284 sw.add(treeview)
285 vbox.pack_start(sw,True,True)
286
287 clear = gtk.Button(None,gtk.STOCK_CLEAR)
288 clear.connect("clicked", on_clear_button_clicked, treeview, store)
289 vbox.pack_start(clear, False, False)
290
291 notebook.append_page(vbox,gtk.Label(_('Relationship Database')))
292
293 converterTreeView = tree.get_widget("dataConversionsTreeView")
294 converterTreeView.set_model(converterListStore)
295 converterTreeView.append_column(gtk.TreeViewColumn(_("Conversions Available"),
296 gtk