Fix shared library names.
[samba-gtk.git] / gtkldb.py
1 #!/usr/bin/python
2
3 # Unix SMB/CIFS implementation.
4 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
5 #   
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
10 #   
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #   
16 # You should have received a copy of the GNU General Public License
17 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #
19
20 """Simple GTK+ frontend for LDB."""
21
22 import gtk
23 import gobject
24 import ldb
25 import os
26 import sys
27
28 class LdbURLDialog(gtk.Dialog):
29     """Dialog that prompts for a LDB URL.
30
31     Ideally this should remember LDB urls and list them in a combo box.
32     """
33     def __init__(self, parent=None):
34         """Create a new LdbURLDialog. 
35
36         :param parent: Parent window.
37         """
38         super(LdbURLDialog, self).__init__(parent=parent, 
39                 buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)
40                 )
41         self.vbox.add(gtk.Label("Enter URL:"))
42         self.url = gtk.Entry()
43         self.vbox.add(self.url)
44         self.show_all()
45
46     def get_url(self):
47         return self.url.get_text()
48
49
50 def Ldb(url):
51     """Create a new LDB object.
52     
53     :param url: LDB URL to connect to.
54     """
55     ret = ldb.Ldb()
56     path = os.getenv("LDB_MODULES_PATH")
57     if path is not None:
58         ret.set_modules_dir(path)
59     ret.connect(url)
60     return ret
61
62
63 class LdbBrowser(gtk.Window):
64     """GTK+ based LDB browser.
65     """
66     def set_ldb(self, ldb):
67         """Change the LDB object displayed.
68
69         Will refresh the window.
70         
71         :param ldb: New LDB object to use.
72         """
73         self.ldb = ldb
74         self.menu_disconnect.set_sensitive(True)
75         self._fill_tree()
76
77     def _cb_connect(self, button):
78         dialog = LdbURLDialog()
79         if dialog.run() == gtk.RESPONSE_OK:
80             self.set_ldb(Ldb(dialog.get_url()))
81         dialog.destroy()
82
83     def _cb_open(self, button):
84         dialog = gtk.FileChooserDialog(title="Please choose a file", 
85                                        parent=self,
86                                       buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
87         if dialog.run() == gtk.RESPONSE_OK:
88             self.set_ldb(Ldb(dialog.get_filename()))
89
90         dialog.destroy()
91
92     def _cb_disconnect(self, button):
93         self.treemodel.clear()
94         self.attributemodel.clear()
95         self.menu_disconnect.set_sensitive(False)
96         self.ldb = None
97
98     def _fill_tree(self, hide_special=False):
99         self.treemodel.clear()
100         paths = {}
101         def add_node(dn):
102             if dn.is_special() and hide_special:
103                 return None
104             if paths.has_key(str(dn)):
105                 return paths[str(dn)]
106             parent_dn = dn.parent()
107             text = str(dn)
108             if parent_dn is not None and str(parent_dn) != '':
109                 parent = add_node(parent_dn)
110                 text = text[:-len(str(parent_dn))].rstrip(",")
111             else:
112                 parent = None
113             paths[str(dn)] = self.treemodel.append(parent, [text, dn])
114
115         for msg in self.ldb.search(None, ldb.SCOPE_SUBTREE, None, ["dn"]):
116             add_node(msg.dn)
117
118     def _toggle_special_entries(self, item):
119         self._fill_tree(item.get_active())
120
121     def _treeview_cursor_cb(self, item):
122         (model, iter) = item.get_selection().get_selected()
123         dn = model.get_value(iter, 1)
124         self.attributemodel.clear()
125         msg = self.ldb.search(dn, ldb.SCOPE_BASE)[0]
126         for name in msg:
127             el = msg[name]
128             for val in set(el):
129                 self.attributemodel.append([name, val, el])
130
131     def __init__(self):
132         super(LdbBrowser, self).__init__()
133         vbox = gtk.VBox(spacing=0)
134         
135         # Menu
136         self.menu = gtk.MenuBar()
137         menuitem_db = gtk.MenuItem("_Database")
138         menu_db = gtk.Menu()
139         menuitem_db.set_submenu(menu_db)
140         self.menu.add(menuitem_db)
141
142         # Database menu
143         menu_connect = gtk.MenuItem("Connect to _URL...")
144         menu_connect.connect('activate', self._cb_connect)
145         menu_db.add(menu_connect)
146
147         menu_open = gtk.MenuItem("Open _File...")
148         menu_open.connect('activate', self._cb_open)
149         menu_db.add(menu_open)
150
151         self.menu_disconnect = gtk.MenuItem("_Disconnect")
152         self.menu_disconnect.connect('activate', self._cb_disconnect)
153         self.menu_disconnect.set_sensitive(False)
154         menu_db.add(self.menu_disconnect)
155
156         menu_db.add(gtk.SeparatorMenuItem())
157         menu_hide_special = gtk.CheckMenuItem("_Hide special entries")
158         menu_hide_special.connect('toggled', self._toggle_special_entries)
159         menu_db.add(menu_hide_special)
160
161         menu_db.add(gtk.SeparatorMenuItem())
162         menu_exit = gtk.ImageMenuItem(gtk.STOCK_QUIT)
163         menu_exit.connect('activate', lambda x: gtk.main_quit())
164
165         menu_db.add(menu_exit)
166
167         vbox.pack_start(self.menu, expand=False)
168
169         self.treeview = gtk.TreeView()
170         self.treemodel = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
171         self.treeview.set_model(self.treemodel)
172         self.treeview.set_headers_visible(False)
173         self.treeview.append_column(gtk.TreeViewColumn("_Dn", 
174                                     gtk.CellRendererText(), text=0))
175         self.treeview.connect("cursor-changed", self._treeview_cursor_cb)
176         self.attributeview = gtk.TreeView()
177         self.attributemodel = gtk.ListStore(str, str, gobject.TYPE_PYOBJECT)
178         self.attributeview.set_model(self.attributemodel)
179         self.attributeview.append_column(gtk.TreeViewColumn("_Name", 
180                                          gtk.CellRendererText(), text=0))
181         self.attributeview.append_column(gtk.TreeViewColumn("_Value", 
182                                          gtk.CellRendererText(), text=1))
183         pane = gtk.HPaned()
184         pane.set_position(200)
185         treeview_window = gtk.ScrolledWindow()
186         treeview_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
187         treeview_window.add(self.treeview)
188         pane.pack1(treeview_window, resize=False, shrink=True)
189         attributeview_window = gtk.ScrolledWindow()
190         attributeview_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
191         attributeview_window.add(self.attributeview)
192         pane.pack2(attributeview_window, shrink=True)
193         vbox.pack_start(pane, fill=True, expand=True)
194
195         self.statusbar = gtk.Statusbar()
196         vbox.pack_end(self.statusbar, expand=False)
197
198         self.add(vbox)
199         self.set_default_size(700, 500)
200         self.show_all()
201
202
203 browser = LdbBrowser()
204 if len(sys.argv) > 1:
205     browser.set_ldb(Ldb(sys.argv[1]))
206 gtk.main()