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