In the "Games" filter, 27_3draw was showing up as 273draw with the 3 underlined....
[fpdb-dooglus.git] / pyfpdb / GuiDatabase.py
blobc6763a3f7d2d073f47f365c484d6a3e190aafedb
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
4 #Copyright 2008-2011 Carl Gherardi
5 #This program is free software: you can redistribute it and/or modify
6 #it under the terms of the GNU Affero General Public License as published by
7 #the Free Software Foundation, version 3 of the License.
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.
14 #You should have received a copy of the GNU Affero General Public License
15 #along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #In the "official" distribution you can find the license in agpl-3.0.txt.
18 import L10n
19 _ = L10n.get_translation()
21 import os
22 import sys
23 import traceback
24 import Queue
25 import re
27 import pygtk
28 pygtk.require('2.0')
29 import gtk
30 import gobject
31 import pango
33 import logging
34 # logging has been set up in fpdb.py or HUD_main.py, use their settings:
35 log = logging.getLogger("maintdbs")
37 import Exceptions
38 import Configuration
39 import Database
40 import SQL
42 class GuiDatabase:
44 # columns in liststore:
45 MODEL_DBMS = 0
46 MODEL_NAME = 1
47 MODEL_DESC = 2
48 MODEL_USER = 3
49 MODEL_PASS = 4
50 MODEL_HOST = 5
51 MODEL_DFLT = 6
52 MODEL_DFLTIC = 7
53 MODEL_STATUS = 8
54 MODEL_STATIC = 9
56 # columns in listview:
57 COL_DBMS = 0
58 COL_NAME = 1
59 COL_DESC = 2
60 COL_USER = 3
61 COL_PASS = 4
62 COL_HOST = 5
63 COL_DFLT = 6
64 COL_ICON = 7
66 def __init__(self, config, mainwin, dia):
67 self.config = config
68 self.main_window = mainwin
69 self.dia = dia
71 try:
72 #self.dia.set_modal(True)
73 self.vbox = self.dia.vbox
74 self.action_area = self.dia.action_area
75 #gtk.Widget.set_size_request(self.vbox, 700, 400);
77 h = gtk.HBox(False, spacing=3)
78 h.show()
79 self.vbox.pack_start(h, padding=3)
81 vbtn = gtk.VBox(True, spacing=3)
82 vbtn.show()
83 h.pack_start(vbtn, expand=False, fill=False, padding=2)
85 # list of databases in self.config.supported_databases:
86 self.liststore = gtk.ListStore(str, str, str, str, str
87 ,str, str, str, str, str)
88 # dbms, name, comment, user, passwd, host, "", default_icon, status, icon
89 # this is how to add a filter:
91 # # Creation of the filter, from the model
92 # filter = self.liststore.filter_new()
93 # filter.set_visible_column(1)
95 # # The TreeView gets the filter as model
96 # self.listview = gtk.TreeView(filter)
97 self.listview = gtk.TreeView(model=self.liststore)
98 self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE)
99 self.listcols = []
100 self.changes = False
102 self.scrolledwindow = gtk.ScrolledWindow()
103 self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
104 self.scrolledwindow.add(self.listview)
105 h.pack_start(self.scrolledwindow, expand=True, fill=True, padding=0)
107 add_button = SideButton(_("_Add"), gtk.STOCK_ADD)
108 add_button.connect("clicked", self.addDB, None)
109 vbtn.pack_start(add_button, False, False, 3)
111 refresh_button = SideButton(_("_Refresh"), gtk.STOCK_REFRESH)
112 refresh_button.connect("clicked", self.refresh, None)
113 vbtn.pack_start(refresh_button, False, False, 3)
115 col = self.addTextColumn(_("Type"), 0, False)
116 col = self.addTextColumn(_("Name"), 1, False)
117 col = self.addTextColumn(_("Description"), 2, True)
118 col = self.addTextColumn(_("Username"), 3, True)
119 col = self.addTextColumn(_("Password"), 4, True)
120 col = self.addTextColumn(_("Host"), 5, True)
121 col = self.addTextObjColumn(_("Open"), 6, 6)
122 col = self.addTextObjColumn(_("Status"), 7, 8)
124 #self.listview.get_selection().set_mode(gtk.SELECTION_SINGLE)
125 #self.listview.get_selection().connect("changed", self.on_selection_changed)
126 self.listview.add_events(gtk.gdk.BUTTON_PRESS_MASK)
127 self.listview.connect('button_press_event', self.selectTest)
129 self.dia.show_all()
130 self.loadDbs()
132 #self.dia.connect('response', self.dialog_response_cb)
133 except:
134 err = traceback.extract_tb(sys.exc_info()[2])[-1]
135 print 'guidbmaint: '+ err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
137 def dialog_response_cb(self, dialog, response_id):
138 # this is called whether close button is pressed or window is closed
139 log.info('dialog_response_cb: response_id='+str(response_id))
140 #if self.changes:
141 # self.config.save()
142 dialog.destroy()
143 return(response_id)
146 def get_dialog(self):
147 return self.dia
149 def addTextColumn(self, title, n, editable=False):
150 col = gtk.TreeViewColumn(title)
151 self.listview.append_column(col)
153 cRender = gtk.CellRendererText()
154 cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR)
155 cRender.set_property('editable', editable)
156 cRender.connect('edited', self.edited_cb, (self.liststore,n))
158 col.pack_start(cRender, True)
159 col.add_attribute(cRender, 'text', n)
160 col.set_max_width(1000)
161 col.set_spacing(0) # no effect
162 self.listcols.append(col)
163 col.set_clickable(True)
164 col.connect("clicked", self.sortCols, n)
166 return(col)
168 def edited_cb(self, cell, path, new_text, user_data):
169 liststore, col = user_data
170 log.info('edited_cb: col = '+str(col))
171 valid = True
172 name = self.liststore[path][self.COL_NAME]
174 # Validate new value (only for dbms so far, but dbms now not updateable so no validation at all!)
175 #if col == self.COL_DBMS:
176 # if new_text not in Configuration.DATABASE_TYPES:
177 # valid = False
179 if valid:
180 self.liststore[path][col] = new_text
182 self.config.set_db_parameters( db_server = self.liststore[path][self.COL_DBMS]
183 , db_name = name
184 , db_desc = self.liststore[path][self.COL_DESC]
185 , db_ip = self.liststore[path][self.COL_HOST]
186 , db_user = self.liststore[path][self.COL_USER]
187 , db_pass = self.liststore[path][self.COL_PASS] )
188 self.changes = True
189 return
191 def check_new_name(self, path, new_text):
192 name_ok = True
193 for i,db in enumerate(self.liststore):
194 if i != path and new_text == db[self.COL_NAME]:
195 name_ok = False
196 #TODO: popup an error message telling user names must be unique
197 return name_ok
199 def addTextObjColumn(self, title, viewcol, storecol, editable=False):
200 col = gtk.TreeViewColumn(title)
201 self.listview.append_column(col)
203 cRenderT = gtk.CellRendererText()
204 cRenderT.set_property("wrap-mode", pango.WRAP_WORD_CHAR)
205 col.pack_start(cRenderT, False)
206 col.add_attribute(cRenderT, 'text', storecol)
208 cRenderP = gtk.CellRendererPixbuf()
209 col.pack_start(cRenderP, True)
210 col.add_attribute(cRenderP, 'stock-id', storecol+1)
212 col.set_max_width(1000)
213 col.set_spacing(0) # no effect
214 self.listcols.append(col)
216 col.set_clickable(True)
217 col.connect("clicked", self.sortCols, viewcol)
218 return(col)
220 def selectTest(self, widget, event):
221 if event.button == 1: # and event.type == gtk.gdk._2BUTTON_PRESS:
222 pthinfo = self.listview.get_path_at_pos( int(event.x), int(event.y) )
223 if pthinfo is not None:
224 path, col, cellx, celly = pthinfo
225 row = path[0]
226 if col == self.listcols[self.COL_DFLT]:
227 if self.liststore[row][self.MODEL_STATUS] == 'ok' and self.liststore[row][self.MODEL_DFLTIC] is None:
228 self.setDefaultDB(row)
230 def setDefaultDB(self, row):
231 print "set new defaultdb:", row, self.liststore[row][self.MODEL_NAME]
232 for r in xrange(len(self.liststore)):
233 if r == row:
234 self.liststore[r][self.MODEL_DFLTIC] = gtk.STOCK_APPLY
235 default = "True"
236 else:
237 self.liststore[r][self.MODEL_DFLTIC] = None
238 default = "False"
240 self.config.set_db_parameters( db_server = self.liststore[r][self.COL_DBMS]
241 , db_name = self.liststore[r][self.COL_NAME]
242 , db_desc = self.liststore[r][self.COL_DESC]
243 , db_ip = self.liststore[r][self.COL_HOST]
244 , db_user = self.liststore[r][self.COL_USER]
245 , db_pass = self.liststore[r][self.COL_PASS]
246 , default = default
248 self.changes = True
249 return
252 def loadDbs(self):
254 self.liststore.clear()
255 #self.listcols = []
256 dia = InfoBox( parent=self.dia, str1=_('Testing database connections ... ') )
257 while gtk.events_pending():
258 gtk.main_iteration()
260 try:
261 # want to fill: dbms, name, comment, user, passwd, host, default, status, icon
262 for name in self.config.supported_databases: #db_ip/db_user/db_pass/db_server
263 dbms = self.config.supported_databases[name].db_server # mysql/postgresql/sqlite
264 dbms_num = self.config.get_backend(dbms) # 2 / 3 / 4
265 comment = self.config.supported_databases[name].db_desc
266 if dbms == 'sqlite':
267 user = ""
268 passwd = ""
269 else:
270 user = self.config.supported_databases[name].db_user
271 passwd = self.config.supported_databases[name].db_pass
272 host = self.config.supported_databases[name].db_ip
273 default = (name == self.config.db_selected)
274 default_icon = None
275 if default: default_icon = gtk.STOCK_APPLY
277 status, err_msg, icon = GuiDatabase.testDB(self.config, dbms, dbms_num, name, user, passwd, host)
279 b = gtk.Button(name)
280 b.show()
281 iter = self.liststore.append( (dbms, name, comment, user, passwd, host, "", default_icon, status, icon) )
283 dia.add_msg( _("finished."), False, True )
284 self.listview.show()
285 self.scrolledwindow.show()
286 self.vbox.show()
287 self.dia.set_focus(self.listview)
289 self.vbox.show_all()
290 self.dia.show()
291 except:
292 err = traceback.extract_tb(sys.exc_info()[2])[-1]
293 print _('loadDbs error: ')+str(dbms_num)+','+host+','+name+','+user+','+passwd+' failed: ' \
294 + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
296 def sortCols(self, col, n):
297 try:
298 log.info('sortcols n='+str(n))
299 if not col.get_sort_indicator() or col.get_sort_order() == gtk.SORT_ASCENDING:
300 col.set_sort_order(gtk.SORT_DESCENDING)
301 else:
302 col.set_sort_order(gtk.SORT_ASCENDING)
303 self.liststore.set_sort_column_id(n, col.get_sort_order())
304 #self.liststore.set_sort_func(n, self.sortnums, (n,grid))
305 log.info('sortcols len(listcols)='+str(len(self.listcols)))
306 for i in xrange(len(self.listcols)):
307 log.info('sortcols i='+str(i))
308 self.listcols[i].set_sort_indicator(False)
309 self.listcols[n].set_sort_indicator(True)
310 # use this listcols[col].set_sort_indicator(True)
311 # to turn indicator off for other cols
312 except:
313 err = traceback.extract_tb(sys.exc_info()[2])
314 print _("***sortCols error: ") + str(sys.exc_info()[1])
315 print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
316 log.info(_('sortCols error: ') + str(sys.exc_info()) )
318 def refresh(self, widget, data):
319 self.loadDbs()
321 def addDB(self, widget, data):
322 adb = AddDB(self.config, self.dia)
323 (status, err_msg, icon, dbms, dbms_num, name, comment, user, passwd, host) = adb.run()
324 adb.destroy()
326 # save in liststore
327 if status == 'ok':
328 iter = self.liststore.append( (dbms, name, comment, user, passwd, host, "", None, status, icon) )
330 # keep config save code in line with edited_cb()? call common routine?
332 valid = True
333 # Validate new value (only for dbms so far, but dbms now not updateable so no validation at all!)
334 #if col == self.COL_DBMS:
335 # if new_text not in Configuration.DATABASE_TYPES:
336 # valid = False
338 if valid:
339 self.config.add_db_parameters( db_server = dbms
340 , db_name = name
341 , db_desc = comment
342 , db_ip = host
343 , db_user = user
344 , db_pass = passwd )
345 self.config.save()
346 self.changes = False
349 @staticmethod
350 def testDB(config, dbms, dbms_num, name, user, passwd, host):
351 status = ""
352 icon = None
353 err_msg = ""
355 sql = SQL.Sql(db_server=dbms)
356 db = Database.Database(config, sql = sql, autoconnect = False)
357 # try to connect to db, set status and err_msg if it fails
358 try:
359 # is creating empty db for sqlite ... mod db.py further?
360 # add noDbTables flag to db.py?
361 log.debug("testDB: " + _("trying to connect to:") + " %s/%s, %s, %s/%s" % (str(dbms_num),dbms,name,user,passwd))
362 db.connect(backend=dbms_num, host=host, database=name, user=user, password=passwd, create=False)
363 if db.connected:
364 log.debug(_("connected ok"))
365 status = 'ok'
366 icon = gtk.STOCK_APPLY
367 if db.wrongDbVersion:
368 status = 'old'
369 icon = gtk.STOCK_INFO
370 else:
371 log.debug(_("not connected but no exception"))
372 except Exceptions.FpdbMySQLAccessDenied:
373 err_msg = _("MySQL Server reports: Access denied. Are your permissions set correctly?")
374 status = "failed"
375 icon = gtk.STOCK_CANCEL
376 except Exceptions.FpdbMySQLNoDatabase:
377 err_msg = _("MySQL client reports: 2002 or 2003 error. Unable to connect - ") \
378 + _("Please check that the MySQL service has been started")
379 status = "failed"
380 icon = gtk.STOCK_CANCEL
381 except Exceptions.FpdbPostgresqlAccessDenied:
382 err_msg = _("PostgreSQL Server reports: Access denied. Are your permissions set correctly?")
383 status = "failed"
384 except Exceptions.FpdbPostgresqlNoDatabase:
385 err_msg = _("PostgreSQL client reports: Unable to connect - ") \
386 + _("Please check that the PostgreSQL service has been started")
387 status = "failed"
388 icon = gtk.STOCK_CANCEL
389 except:
390 # add more specific exceptions here if found (e.g. for sqlite?)
391 err = traceback.extract_tb(sys.exc_info()[2])[-1]
392 err_msg = err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
393 status = "failed"
394 icon = gtk.STOCK_CANCEL
395 if err_msg:
396 log.info( _('db connection to %s, %s, %s, %s, %s failed: %s') % (str(dbms_num), host, name, user, passwd, err_msg))
398 return( status, err_msg, icon )
401 class AddDB(gtk.Dialog):
403 def __init__(self, config, parent):
404 log.debug(_("AddDB starting"))
405 self.dbnames = { 'Sqlite' : Configuration.DATABASE_TYPE_SQLITE
406 , 'MySQL' : Configuration.DATABASE_TYPE_MYSQL
407 , 'PostgreSQL' : Configuration.DATABASE_TYPE_POSTGRESQL
409 self.config = config
410 # create dialog and add icon and label
411 super(AddDB,self).__init__( parent=parent
412 , flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT
413 , title=_("Add New Database")
414 , buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT
415 ,gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)
416 ) # , buttons=btns
417 self.set_default_size(450, 280)
418 #self.connect('response', self.response_cb)
420 t = gtk.Table(5, 3, True)
421 self.vbox.pack_start(t, expand=False, fill=False, padding=3)
423 l = gtk.Label( _("DB Type") )
424 l.set_alignment(1.0, 0.5)
425 t.attach(l, 0, 1, 0, 1, xpadding=3)
426 self.cb_dbms = gtk.combo_box_new_text()
427 for s in ('Sqlite',): # keys(self.dbnames):
428 self.cb_dbms.append_text(s)
429 self.cb_dbms.set_active(0)
430 t.attach(self.cb_dbms, 1, 3, 0, 1, xpadding=3)
431 self.cb_dbms.connect("changed", self.db_type_changed, None)
433 l = gtk.Label( _("DB Name") )
434 l.set_alignment(1.0, 0.5)
435 t.attach(l, 0, 1, 1, 2, xpadding=3)
436 self.e_db_name = gtk.Entry()
437 self.e_db_name.set_width_chars(15)
438 t.attach(self.e_db_name, 1, 3, 1, 2, xpadding=3)
439 self.e_db_name.connect("focus-out-event", self.db_name_changed, None)
441 l = gtk.Label( _("DB Description") )
442 l.set_alignment(1.0, 0.5)
443 t.attach(l, 0, 1, 2, 3, xpadding=3)
444 self.e_db_desc = gtk.Entry()
445 self.e_db_desc.set_width_chars(15)
446 t.attach(self.e_db_desc, 1, 3, 2, 3, xpadding=3)
448 self.l_username = gtk.Label( _("Username") )
449 self.l_username.set_alignment(1.0, 0.5)
450 t.attach(self.l_username, 0, 1, 3, 4, xpadding=3)
451 self.e_username = gtk.Entry()
452 self.e_username.set_width_chars(15)
453 t.attach(self.e_username, 1, 3, 3, 4, xpadding=3)
455 self.l_password = gtk.Label( _("Password") )
456 self.l_password.set_alignment(1.0, 0.5)
457 t.attach(self.l_password, 0, 1, 4, 5, xpadding=3)
458 self.e_password = gtk.Entry()
459 self.e_password.set_width_chars(15)
460 t.attach(self.e_password, 1, 3, 4, 5, xpadding=3)
462 self.l_host = gtk.Label( _("Host Computer") )
463 self.l_host.set_alignment(1.0, 0.5)
464 t.attach(self.l_host, 0, 1, 5, 6, xpadding=3)
465 self.e_host = gtk.Entry()
466 self.e_host.set_width_chars(15)
467 self.e_host.set_text("localhost")
468 t.attach(self.e_host, 1, 3, 5, 6, xpadding=3)
470 parent.show_all()
471 self.show_all()
473 # hide username/password fields as not used by sqlite
474 self.l_username.hide()
475 self.e_username.hide()
476 self.l_password.hide()
477 self.e_password.hide()
479 def run(self):
480 response = super(AddDB,self).run()
481 log.debug(_("addDB.run: response is %s, accept is %s") % (str(response), str(int(gtk.RESPONSE_ACCEPT))))
483 ok,retry = False,True
484 while response == gtk.RESPONSE_ACCEPT:
485 ok,retry = self.check_fields()
486 if retry:
487 response = super(AddDB,self).run()
488 else:
489 response = gtk.RESPONSE_REJECT
491 (status, err_msg, icon, dbms, dbms_num
492 ,name, db_desc, user, passwd, host) = ("error", "error", None, None, None
493 ,None, None, None, None, None)
494 if ok:
495 log.debug(_("start creating new db"))
496 # add a new db
497 master_password = None
498 dbms = self.dbnames[ self.cb_dbms.get_active_text() ]
499 dbms_num = self.config.get_backend(dbms)
500 name = self.e_db_name.get_text()
501 db_desc = self.e_db_desc.get_text()
502 user = self.e_username.get_text()
503 passwd = self.e_password.get_text()
504 host = self.e_host.get_text()
506 # TODO:
507 # if self.cb_dbms.get_active_text() == 'Postgres':
508 # <ask for postgres master password>
510 # create_db() in Database.py or here? ... TODO
512 # test db after creating?
513 status, err_msg, icon = GuiDatabase.testDB(self.config, dbms, dbms_num, name, user, passwd, host)
514 log.debug(_('tested new db, result=%s') % str((status,err_msg)))
515 if status == 'ok':
516 #dia = InfoBox( parent=self, str1=_('Database created') )
517 str1 = _('Database created')
518 else:
519 #dia = InfoBox( parent=self, str1=_('Database creation failed') )
520 str1 = _('Database creation failed')
521 #dia.add_msg("", True, True)
522 btns = (gtk.BUTTONS_OK)
523 dia = gtk.MessageDialog( parent=self, flags=gtk.DIALOG_DESTROY_WITH_PARENT
524 , type=gtk.MESSAGE_INFO, buttons=(btns), message_format=str1 )
525 dia.run()
527 return( (status, err_msg, icon, dbms, dbms_num, name, db_desc, user, passwd, host) )
529 def check_fields(self):
530 """check fields and return true/false according to whether user wants to try again
531 return False if fields are ok
533 log.debug(_("check_fields: starting"))
534 try_again = False
535 ok = True
537 # checks for all db's
538 if self.e_db_name.get_text() == "":
539 msg = _("No Database Name given")
540 ok = False
541 elif self.e_db_desc.get_text() is None or self.e_db_desc.get_text() == "":
542 msg = _("No Database Description given")
543 ok = False
544 elif self.cb_dbms.get_active_text() != 'Sqlite' and self.e_username.get_text() == "":
545 msg = _("No Username given")
546 ok = False
547 elif self.cb_dbms.get_active_text() != 'Sqlite' and self.e_password.get_text() == "":
548 msg = _("No Password given")
549 ok = False
550 elif self.e_host.get_text() == "":
551 msg = _("No Host given")
552 ok = False
554 if ok:
555 if self.cb_dbms.get_active_text() == 'Sqlite':
556 # checks for sqlite
557 pass
558 elif self.cb_dbms.get_active_text() == 'MySQL':
559 # checks for mysql
560 pass
561 elif self.cb_dbms.get_active_text() == 'Postgres':
562 # checks for postgres
563 pass
564 else:
565 msg = _("Unknown Database Type selected")
566 ok = False
568 if not ok:
569 log.debug(_("check_fields: open dialog"))
570 dia = gtk.MessageDialog( parent=self
571 , flags=gtk.DIALOG_DESTROY_WITH_PARENT
572 , type=gtk.MESSAGE_ERROR
573 , message_format=msg
574 , buttons = gtk.BUTTONS_YES_NO
576 #l = gtk.Label(msg)
577 #dia.vbox.add(l)
578 l = gtk.Label( _("Do you want to try again?") )
579 dia.vbox.add(l)
580 dia.show_all()
581 ret = dia.run()
582 #log.debug(_("check_fields: ret is %s cancel is %s") % (str(ret), str(int(gtk.RESPONSE_CANCEL))))
583 if ret == gtk.RESPONSE_YES:
584 try_again = True
585 #log.debug(_("check_fields: destroy dialog"))
586 dia.hide()
587 dia.destroy()
589 #log.debug(_("check_fields: returning ok as %s, try_again as %s") % (str(ok), str(try_again)))
590 return(ok,try_again)
592 def db_type_changed(self, widget, data):
593 if self.cb_dbms.get_active_text() == 'Sqlite':
594 self.l_username.hide()
595 self.e_username.hide()
596 self.e_username.set_text("")
597 self.l_password.hide()
598 self.e_password.hide()
599 self.e_password.set_text("")
600 else:
601 self.l_username.show()
602 self.e_username.show()
603 self.l_password.show()
604 self.e_password.show()
605 return(response)
607 def db_name_changed(self, widget, event, data):
608 log.debug('db_name_changed: text='+widget.get_text())
609 if not re.match('\....$', widget.get_text()):
610 widget.set_text(widget.get_text()+'.db3')
611 widget.show()
613 #def response_cb(self, dialog, data):
614 # dialog.destroy()
615 # return(data)
618 class InfoBox(gtk.Dialog):
620 def __init__(self, parent, str1):
621 # create dialog and add icon and label
622 btns = (gtk.BUTTONS_OK)
623 btns = None
624 # messagedialog puts text in inverse colors if no buttons are displayed??
625 #dia = gtk.MessageDialog( parent=self.main_window, flags=gtk.DIALOG_DESTROY_WITH_PARENT
626 # , type=gtk.MESSAGE_INFO, buttons=(btns), message_format=str1 )
627 # so just use Dialog instead
628 super(InfoBox,self).__init__( parent=parent
629 , flags=gtk.DIALOG_DESTROY_WITH_PARENT
630 , title="" ) # , buttons=btns
632 h = gtk.HBox(False, 2)
633 i = gtk.Image()
634 i.set_from_stock(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_DIALOG)
635 l = gtk.Label(str1)
636 h.pack_start(i, padding=5)
637 h.pack_start(l, padding=5)
638 self.vbox.pack_start(h)
639 parent.show_all()
640 self.show_all()
642 def add_msg(self, str1, run, destroy):
643 # add extra label
644 self.vbox.pack_start( gtk.Label(str1) )
645 self.show_all()
646 response = None
647 if run: response = self.run()
648 if destroy: self.destroy()
649 return (response)
652 class SideButton(gtk.Button):
653 """Create a button with the label below the icon"""
655 # to change label on buttons:
656 # ( see http://faq.pygtk.org/index.py?req=show&file=faq09.005.htp )
657 # gtk.stock_add([(gtk.STOCK_ADD, _("Add"), 0, 0, "")])
659 # alternatively:
660 # button = gtk.Button(stock=gtk.STOCK_CANCEL)
661 # button.show()
662 # alignment = button.get_children()[0]
663 # hbox = alignment.get_children()[0]
664 # image, label = hbox.get_children()
665 # label.set_text('Hide')
667 def __init__(self, label=None, stock=None, use_underline=True):
668 gtk.stock_add([(stock, label, 0, 0, "")])
670 super(SideButton, self).__init__(label=label, stock=stock, use_underline=True)
671 alignment = self.get_children()[0]
672 hbox = alignment.get_children()[0]
673 image, label = hbox.get_children()
674 #label.set_text('Hide')
675 hbox.remove(image)
676 hbox.remove(label)
677 v = gtk.VBox(False, spacing=3)
678 v.pack_start(image, 3)
679 v.pack_start(label, 3)
680 alignment.remove(hbox)
681 alignment.add(v)
682 self.show_all()
686 if __name__=="__main__":
688 config = Configuration.Config()
690 win = gtk.Window(gtk.WINDOW_TOPLEVEL)
691 win.set_title(_("Log Viewer"))
692 win.set_border_width(1)
693 win.set_default_size(600, 500)
694 win.set_resizable(True)
696 dia = gtk.Dialog(_("Log Viewer"),
697 win,
698 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
699 (gtk.STOCK_CLOSE, gtk.RESPONSE_OK))
700 dia.set_default_size(500, 500)
701 log = GuiLogView(config, win, dia.vbox)
702 response = dia.run()
703 if response == gtk.RESPONSE_ACCEPT:
704 pass
705 dia.destroy()