Run localization on controllers file
[ipypbx] / src / ipypbx / controllers.py
1 # Copyright (c) Stas Shtin, 2010
2
3 # This file is part of IPyPBX.
4
5 # IPyPBX is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9
10 # IPyPBX is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14
15 # You should have received a copy of the GNU General Public License
16 # along with IPyPBX.  If not, see <http://www.gnu.org/licenses/>.
17
18 from PyQt4 import QtCore, QtGui, QtSql
19
20
21 class BaseController(QtCore.QObject):
22     """
23     Base class for other controllers.
24
25     Doesn't do anything useful on its own.
26     """
27     # TODO: possibly use a separate class for options and a meta-class.
28     fields = ()
29     view_list_fields = ()
30     view_display_fields = ()
31     view_display_fields_hidden = ()
32     
33     def __init__(self, model=None, view_list=None, view_display=None, parent=None, views=None):
34         super(BaseController, self).__init__(parent=parent)
35
36         self.views = views
37         
38         # Find out base name.
39         classname = self.__class__.__name__
40         self.basename = (
41             classname[:-10] if classname.endswith('Controller')
42             else classname)
43         self.basename = self.basename[0].lower() + self.basename[1:]
44
45         # Are we given an existing model?
46         if model:
47             self.model = model
48         # Otherwise initialize a new model.
49         else:
50             self.model = QtSql.QSqlTableModel(parent)
51             self.model.setTable('ipypbxweb_%s' % self.basename.lower())
52
53             # Create model header from fields list.
54             for i, field in enumerate(self.fields):
55                 self.model.setHeaderData(
56                     i, QtCore.Qt.Horizontal, QtCore.QVariant(field))
57
58             # Fetch model data.
59             self.model.select()
60
61         # Are we given an existing view list?
62         if view_list:
63             self.view_list = view_list
64         # Otherwise get view list from the parent.            
65         else:
66             self.view_list = getattr(views, self.basename + 'ViewList')
67             self.view_list.setModel(self.model)
68
69             # Hide fields not meant for display.
70             for i, field in enumerate(self.fields):
71                 if field not in self.view_list_fields:
72                     self.view_list.hideColumn(i)
73
74             # Stretch headers to fill all available width.
75             self.view_list.setSelectionMode(QtGui.QTableView.SingleSelection)
76             self.view_list.setSelectionBehavior(QtGui.QTableView.SelectRows)
77             self.view_list.resizeColumnsToContents()
78             self.view_list.resizeRowsToContents()
79             self.view_list.horizontalHeader().setStretchLastSection(True)
80         self.view_list.selectRow(0)
81
82         # Are we given an existing view display?
83         if view_display:
84             self.view_display = view_display
85         # Otherwise get view display from the parent.
86         else:
87             self.view_display = QtGui.QDataWidgetMapper(parent)
88             self.view_display.setModel(self.model)
89
90             # If view_display_fields is not send, display all fields except
91             # the first one that is usually the ID.
92             display_fields = self.getDisplayFields()
93             for i, field in enumerate(self.fields):
94                 if field in display_fields:
95                     field_widget = self.getFieldWidget(field)
96                     self.view_display.addMapping(field_widget, i)
97
98         # Select first row in the view list.
99         self.view_display.toFirst()
100         
101         # Register signals for this controller.
102         for data in self.getSignalsData():
103             if len(data) == 3:
104                 sender, signal, receiver = data
105                 QtCore.QObject.connect(sender, QtCore.SIGNAL(signal), receiver)
106             elif len(data) == 4:
107                 sender, signal, receiver, slot = data
108                 QtCore.QObject.connect(
109                     sender, QtCore.SIGNAL(signal), receiver, QtCore.SLOT(slot))
110                                        
111
112     def getDisplayFields(self):
113         """
114         Return the list of fields to display.
115
116         If it's not set explicitly, use all defined fields except the first
117         which usually is the primary key.
118         """
119         # Do we have the fields to display explicitly set?
120         if self.view_display_fields:
121             fields = self.view_display_fields
122         else:
123             # Do we have hidden fields set?
124             if self.view_display_fields_hidden:
125                 hidden = self.view_display_fields_hidden
126             # If not, hide the first one.
127             else:
128                 hidden = self.fields[0]
129
130             # Filter away all hidden fields.
131             fields = [field for field in self.fields if not field in hidden]
132             
133         return fields
134
135     def getFieldWidget(self, field):
136         """
137         Return widget for given field name.
138         """
139         return getattr(
140             self.views,
141             self.basename + ''.join(word.capitalize()
142                                     for word in field.split(' ')))
143
144     def getSignalsData(self):
145         """
146         Default signals built from controller's base name.
147         """
148         # Default signals handle row selection, Add and Save buttons.
149         return (
150             (getattr(self.views, self.basename + 'Add'), 'clicked()', self.add),
151             (self.view_list.selectionModel(),
152              'currentRowChanged(QModelIndex,QModelIndex)',
153              self.view_display, 'setCurrentModelIndex(QModelIndex)'),
154             (getattr(self.views, self.basename + 'Save'), 'clicked()',
155              self.save),
156             )
157
158     def add(self):
159         """
160         Add new object.
161         """
162         # Add a new row to list view.
163         num_rows = self.model.rowCount()
164         self.model.insertRows(num_rows, 1)
165         self.view_list.selectRow(num_rows)
166
167         # Disable adding more than one row.
168         self.getFieldWidget('Add').setEnabled(False)
169
170         # Focust to the first displayed field.
171         self.getFieldWidget(self.getDisplayFields()[0]).setFocus()
172
173         # Clear all displayed fields.
174         for field in self.getDisplayFields():
175             self.getFieldWidget(field).clear()
176         
177     def save(self):
178         """
179         Save to database.
180         """
181         # For now we just submit everything - QT seems to be able to handle it
182         # on its own.
183         self.view_display.submit()
184         self.getFieldWidget('Add').setEnabled(True)
185         
186
187
188 class ConnectionController(BaseController):
189     """
190     Connections controller.
191     """
192     fields = (
193         'ID', 'Name', 'Local IP Address', 'Local Port',
194         'Freeswitch IP Address', 'Freeswitch Port')
195     view_list_fields = 'Name', 'Freeswitch IP Address', 'Freeswitch Port'
196     
197     def clone(self):
198         """
199         TODO: Clone an existing connection.
200
201         This creates a new connection with bound data copied from another one.
202         """
203
204 class SipProfileController(BaseController):
205     """
206     SIP Profile controller.
207     """
208     fields = (
209         'ID', 'Connection ID', 'Name', 'External RTP IP', 'External SIP IP',
210         'RTP IP', 'SIP IP', 'SIP Port', 'Accept Blind Registration',
211         'Authenticate Calls', 'Is Active')
212     view_list_fields = 'Name', 'SIP IP', 'SIP Port'
213     view_display_fields_hidden = 'ID', 'Connection ID'
214
215
216 class DomainController(BaseController):
217     """
218     Domain controller.
219     """
220     fields = 'ID', 'SIP Profile ID', 'Host Name', 'Is Active'
221     view_list_fields = 'SIP Profile ID', 'Host Name', 'Is Active'
222
223
224 class GatewayController(BaseController):
225     """
226     Gateway controller.
227     """
228     fields = (
229         'ID', 'SIP Profile ID', 'Name', 'Username', 'Password', 'Realm',
230         'From Domain', 'Expire In Seconds', 'Retry In Seconds',
231         'Caller ID In From Field', 'Is Active')
232     view_list_fields = 'SIP Profile ID', 'Name'
233
234
235 class EndpointController(BaseController):
236     """
237     Endpoint controller.
238     """
239     fields = 'ID', 'User ID', 'Password', 'Domain ID', 'Is Active'
240
241
242 class ExtensionController(BaseController):
243     """
244     Extension controller.
245     """
246     fields = (
247         'ID', 'Destination Match', 'XML Dialplan', 'Domain ID', 'Endpoint ID',
248         'Authenticate Calls', 'Is Active')
249     view_list_fields = 'Destination Match', 'Domain ID', 'Endpoint ID'
250