build: use a common.sh file for common operations
[ugit.git] / ugit / qobserver.py
blob4810a70cff514d0621de92c5b6fdc562099bbaeb
1 #!/usr/bin/env python
2 from PyQt4.QtCore import Qt
3 from PyQt4.QtCore import QObject
4 from PyQt4.QtCore import SIGNAL
5 from PyQt4.QtCore import QDate
6 from PyQt4.QtGui import QDateEdit
7 from PyQt4.QtGui import QSpinBox
8 from PyQt4.QtGui import QPixmap
9 from PyQt4.QtGui import QTextEdit
10 from PyQt4.QtGui import QLineEdit
11 from PyQt4.QtGui import QListWidget
12 from PyQt4.QtGui import QCheckBox
13 from PyQt4.QtGui import QFontComboBox
14 from PyQt4.QtGui import QAbstractButton
15 from PyQt4.QtGui import QSplitter
16 from PyQt4.QtGui import QAction
18 from ugit.observer import Observer
20 class QObserver(Observer, QObject):
22 def __init__(self, model, view):
23 Observer.__init__(self, model)
24 QObject.__init__(self)
26 self.view = view
28 self.__actions = {}
29 self.__callbacks = {}
30 self.__model_to_view = {}
31 self.__view_to_model = {}
32 self.__connected = []
34 def SLOT(self, *args):
35 '''Default slot to handle all Qt callbacks.
36 This method delegates to callbacks from add_signals.'''
38 widget = self.sender()
39 sender = str(widget.objectName())
41 if sender in self.__callbacks:
42 self.__callbacks[sender](*args)
44 elif sender in self.__view_to_model:
45 model = self.model
46 model_param = self.__view_to_model[sender]
47 if isinstance(widget, QTextEdit):
48 value = unicode(widget.toPlainText())
49 model.set_param(model_param, value,
50 notify=False)
51 elif isinstance(widget, QLineEdit):
52 value = unicode(widget.text())
53 model.set_param(model_param, value)
54 elif isinstance(widget, QCheckBox):
55 model.set_param(model_param, widget.isChecked())
56 elif isinstance(widget, QSpinBox):
57 model.set_param(model_param, widget.value())
58 elif isinstance(widget, QFontComboBox):
59 value = unicode(widget.currentFont().toString())
60 model.set_param(model_param, value)
61 elif isinstance(widget, QDateEdit):
62 fmt = Qt.ISODate
63 value = str(widget.date().toString(fmt))
64 model.set_param(model_param, value)
65 else:
66 print("SLOT(): Unknown widget:", sender, widget)
68 def connect(self, obj, signal_str, *args):
69 '''Convenience function so that subclasses do not have
70 to import QtCore.SIGNAL.'''
71 signal = signal_str
72 if type(signal) is str:
73 signal = SIGNAL(signal)
74 return QObject.connect(obj, signal, *args)
76 def add_signals(self, signal_str, *objects):
77 '''Connects object's signal to the QObserver.'''
78 for obj in objects:
79 self.connect(obj, signal_str, self.SLOT)
81 def add_callbacks(self, **callbacks):
82 '''Registers callbacks that are called in response to GUI events.'''
83 for sender, callback in callbacks.iteritems():
84 self.__callbacks[sender] = callback
85 self.autoconnect(getattr(self.view, sender))
87 def add_observables(self, *params):
88 '''This method assumes that widgets and model params
89 share the same name.'''
90 for param in params:
91 self.model_to_view(param, getattr(self.view, param))
93 def model_to_view(self, model_param, *widgets):
94 '''Binds model params to qt widgets(model->view)'''
95 self.__model_to_view[model_param] = widgets
96 for w in widgets:
97 view = str(w.objectName())
98 self.__view_to_model[view] = model_param
99 self.__autoconnect(w)
101 def autoconnect(self, *widgets):
102 for w in widgets:
103 self.__autoconnect(w)
105 def __autoconnect(self, widget):
106 '''Automagically connects Qt widgets to QObserver.SLOT'''
108 if widget in self.__connected: return
109 self.__connected.append(widget)
111 if isinstance(widget, QTextEdit):
112 self.add_signals(
113 'textChanged()', widget)
114 elif isinstance(widget, QLineEdit):
115 self.add_signals(
116 'textChanged(const QString&)', widget)
117 elif isinstance(widget, QListWidget):
118 self.add_signals(
119 'itemSelectionChanged()', widget)
120 self.add_signals(
121 'itemClicked(QListWidgetItem *)', widget)
122 self.add_signals(
123 'itemDoubleClicked(QListWidgetItem*)', widget)
124 elif isinstance(widget, QAbstractButton):
125 self.add_signals(
126 'released()', widget)
127 elif isinstance(widget, QAction):
128 self.add_signals(
129 'triggered()', widget)
130 elif isinstance(widget, QCheckBox):
131 self.add_signals(
132 'stateChanged(int)', widget)
133 elif isinstance(widget, QSpinBox):
134 self.add_signals(
135 'valueChanged(int)', widget)
136 elif isinstance(widget, QFontComboBox):
137 self.add_signals(
138 'currentFontChanged(const QFont&)', widget)
139 elif isinstance(widget, QSplitter):
140 self.add_signals(
141 'splitterMoved(int,int)', widget)
142 elif isinstance(widget, QDateEdit):
143 self.add_signals(
144 'dateChanged(const QDate&)', widget)
145 else:
146 raise Exception(
147 "Asked to connect unknown widget:\n\t"
148 "%s => %s" %( type(widget),
149 str(widget.objectName()) ))
151 def add_actions(self, **kwargs):
152 '''Register view actions that are called in response to
153 view changes.(view->model)'''
154 for model_param, callback in kwargs.iteritems():
155 if type(callback) is list:
156 self.__actions[model_param] = callback
157 else:
158 self.__actions[model_param] = [callback]
160 def subject_changed(self, param, value):
161 '''Sends a model param to the view(model->view)'''
163 if param in self.__model_to_view:
164 notify = self.model.get_notify()
165 self.model.set_notify(False)
166 for widget in self.__model_to_view[param]:
167 if isinstance(widget, QSpinBox):
168 widget.setValue(value)
169 elif isinstance(widget, QPixmap):
170 widget.load(value)
171 elif isinstance(widget, QTextEdit):
172 widget.setText(value)
173 elif isinstance(widget, QLineEdit):
174 widget.setText(value)
175 elif isinstance(widget, QListWidget):
176 widget.clear()
177 for i in value:
178 widget.addItem(i)
179 elif isinstance(widget, QCheckBox):
180 widget.setChecked(value)
181 elif isinstance(widget, QFontComboBox):
182 font = widget.currentFont()
183 font.fromString(value)
184 elif isinstance(widget, QDateEdit):
185 if not value: return
186 fmt = Qt.ISODate
187 date = QDate.fromString(value, fmt)
188 if date:
189 widget.setDate(date)
190 else:
191 print('subject_changed(): '
192 + 'Unknown widget:',
193 str(widget.objectName()),
194 widget, value)
195 self.model.set_notify(notify)
197 if param not in self.__actions:
198 return
199 widgets = []
200 if param in self.__model_to_view:
201 for widget in self.__model_to_view[param]:
202 widgets.append(widget)
203 # Call the model callback w/ the view's widgets as the args
204 for action in self.__actions[param]:
205 action(*widgets)
207 def refresh_view(self, *params):
208 if not params:
209 params= tuple(self.__model_to_view.keys()
210 + self.__actions.keys())
211 notified = []
212 for param in params:
213 if param not in notified:
214 notified.append(param)
215 self.model.notify_observers(*notified)