File: datacreate.py

package info (click to toggle)
veusz 1.15-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 6,276 kB
  • sloc: python: 27,998; cpp: 2,181; xml: 1,693; ansic: 1,310; makefile: 49; sh: 10
file content (329 lines) | stat: -rw-r--r-- 12,516 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
#    Copyright (C) 2006 Jeremy S. Sanders
#    Email: Jeremy Sanders <jeremy@jeremysanders.net>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License along
#    with this program; if not, write to the Free Software Foundation, Inc.,
#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
##############################################################################

"""Dataset creation dialog."""

import veusz.qtall as qt4
import veusz.utils as utils
import veusz.document as document
import veusz.setting as setting
from veuszdialog import VeuszDialog

import dataeditdialog

class _DSException(RuntimeError):
    """A class to handle errors while trying to create datasets."""
    pass

class DataCreateDialog(VeuszDialog):
    """Dialog to create datasets.

    They can be created from numerical ranges, parametrically or from
    expressions involving other dataset."""

    def __init__(self, parent, document):
        """Initialise dialog with document."""

        VeuszDialog.__init__(self, parent, 'datacreate.ui')
        self.document = document

        # create button group to get notification of changes
        self.connect( self.methodGroup, qt4.SIGNAL('radioClicked'),
                      self.slotMethodChanged )

        # connect create button
        self.createbutton = self.buttonBox.addButton(
            "C&reate", qt4.QDialogButtonBox.ApplyRole )
        self.replacebutton = self.buttonBox.addButton(
            "&Replace", qt4.QDialogButtonBox.ApplyRole )

        self.connect( self.buttonBox.button(qt4.QDialogButtonBox.Reset),
                      qt4.SIGNAL('clicked()'), self.resetButtonClicked )

        self.connect( self.createbutton, qt4.SIGNAL('clicked()'),
                      self.createButtonClicked )
        self.connect( self.replacebutton, qt4.SIGNAL('clicked()'),
                      self.createButtonClicked )

        # connect notification of document change
        self.connect( self.document, qt4.SIGNAL("sigModified"),
                      self.modifiedDocSlot )

        # set validators for edit controls
        self.numstepsedit.setValidator( qt4.QIntValidator(1, 99999999, self) )
        self.tstartedit.setValidator( qt4.QDoubleValidator(self) )
        self.tendedit.setValidator( qt4.QDoubleValidator(self) )
        self.tstepsedit.setValidator( qt4.QIntValidator(1, 99999999, self) )

        # connect up edit control to update create button status
        for edit in (self.numstepsedit, self.tstartedit, self.tendedit,
                     self.tstepsedit, self.nameedit,
                     self.valueedit):
            self.connect( edit, qt4.SIGNAL('editTextChanged(const QString &)'),
                          self.editsEditSlot )

        self.connect( self.nameedit, qt4.SIGNAL('currentIndexChanged(int)'),
                      self.datasetSelected )

        # edit controls for dataset
        self.dsedits = { 'data': self.valueedit, 'serr': self.symerroredit,
                         'perr': self.poserroredit, 'nerr': self.negerroredit }
        
        # update button state
        self.editsEditSlot('')

    def slotMethodChanged(self, button):
        """Called when a new data creation method is used."""

        # enable and disable correct widgets depending on method
        isvalue = button is self.valueradio
        self.valuehelperlabel.setVisible(isvalue)
        self.numstepsedit.setEnabled(isvalue)

        isparametric = button is self.parametricradio
        self.parametrichelperlabel.setVisible(isparametric)
        self.tstartedit.setEnabled(isparametric)
        self.tendedit.setEnabled(isparametric)
        self.tstepsedit.setEnabled(isparametric)

        isfunction = button is self.expressionradio
        self.expressionhelperlabel.setVisible(isfunction)

        # enable/disable create button
        self.editsEditSlot('')

    def modifiedDocSlot(self):
        """Update create button if document changes."""
        self.editsEditSlot('')

    def datasetSelected(self, index):
        """If dataset is selected from drop down box, reload entries
        for editing."""

        if index >= 0:
            dsname = unicode( self.nameedit.text() )
            if dsname in self.document.data:
                self.reEditDataset(self.document.data[dsname], dsname)

    def reEditDataset(self, ds, dsname):
        """Given a dataset name, allow it to be edited again
        (if it is editable)."""

        if isinstance(ds, document.DatasetExpression): 
            # change selected method
            if ds.parametric is None:
                # standard expression
                self.expressionradio.click()
            else:
                # parametric dataset
                self.parametricradio.click()
                p = ds.parametric
                self.tstartedit.setText( '%g' % p[0] )
                self.tendedit.setText( '%g' % p[1] )
                self.tstepsedit.setText( str(p[2]) )

            # make sure name is set
            self.nameedit.setText(dsname)
            # set expressions
            for part in self.dsedits.iterkeys():
                text = ds.expr[part]
                if text is None:
                    text = ''
                self.dsedits[part].setText(text)

        elif isinstance(ds, document.DatasetRange):
            # change selected method
            self.valueradio.click()
            # make sure name is set
            self.nameedit.setText(dsname)
            # set expressions
            for part in self.dsedits.iterkeys():
                data = getattr(ds, 'range_%s' % part)
                if data is None:
                    text = ''
                else:
                    text = '%g:%g' % data
                self.dsedits[part].setText(text)

    def editsEditSlot(self, dummytext):
        """Enable/disable createbutton."""

        # dataset name checks
        dstext = unicode(self.nameedit.text())
        dsvalid = utils.validateDatasetName(dstext)
        dsexists = dstext in self.document.data

        # check other edit controls
        method = self.methodGroup.getRadioChecked()
        if method is self.valueradio:
            # value
            editsokay = self.numstepsedit.hasAcceptableInput()
        elif method is self.parametricradio:
            # parametric
            editsokay = (self.tstartedit.hasAcceptableInput() and
                         self.tendedit.hasAcceptableInput() and
                         self.tstepsedit.hasAcceptableInput())
        else:
            # function
            editsokay = True

        # we needs some input on the value
        if len(unicode(self.valueedit.text())) == 0:
            editsokay = False

        # hide / show create button depending whether dataset exists
        self.createbutton.setVisible(not dsexists)
        self.replacebutton.setVisible(dsexists)
        
        # enable buttons if expressions valid
        enabled = dsvalid and editsokay
        self.createbutton.setEnabled(enabled)
        self.replacebutton.setEnabled(enabled)

    def resetButtonClicked(self):
        """Reset button clicked - reset dialog."""

        for cntrl in (self.valueedit, self.symerroredit, self.poserroredit,
                      self.negerroredit, self.numstepsedit,
                      self.tstartedit, self.tendedit, self.tstepsedit,
                      self.nameedit):
            cntrl.setEditText("")
                      
        self.linkcheckbox.setChecked(True)
        self.valueradio.click()

    def createButtonClicked(self):
        """Create button pressed."""
        
        dsname = unicode( self.nameedit.text() )
        dsexists = dsname in self.document.data

        try:
            # select function to create dataset with
            createfn = {
                self.valueradio: self.createFromRange,
                self.parametricradio: self.createParametric,
                self.expressionradio: self.createFromExpression }[
                self.methodGroup.getRadioChecked()]

            # make a new dataset using method
            op = createfn(dsname)
            self.document.applyOperation(op)

            if dsexists:
                status = "Replaced dataset '%s'" % dsname
            else:
                status = "Created dataset '%s'" % dsname
            self.statuslabel.setText(status)

        except (document.CreateDatasetException,
                document.DatasetException, _DSException), e:

            # all bad roads lead here - take exception string and tell user
            if dsexists:
                status = "Replacement failed"
            else:
                status = "Creation failed"
            self.statuslabel.setText(status)
            qt4.QMessageBox.warning(self, "Veusz", unicode(e))
            
    def createFromRange(self, name):
        """Make dataset from a range or constant.
        name is the name of the dataset
        
        Raises _DSException if error
        """

        numsteps = int( unicode(self.numstepsedit.text()) )

        # go over each of the ranges / values
        vals = {}
        for key, cntrl in self.dsedits.iteritems():
            text = unicode( cntrl.text() ).strip()

            if not text:
                continue
                
            if text.find(':') != -1:
                # an actual range
                parts = text.split(':')
                
                if len(parts) != 2:
                    raise _DSException("Incorrect range format, use form 1:10")
                try:
                    minval, maxval = float(parts[0]), float(parts[1])
                except ValueError:
                    raise _DSException("Invalid number in range")

            else:
                try:
                    minval = float(text)
                except ValueError:
                    raise _DSException("Invalid number")
                maxval = minval
                
            vals[key] = (minval, maxval)
            
        linked = self.linkcheckbox.checkState() == qt4.Qt.Checked
        return document.OperationDatasetCreateRange(name, numsteps, vals,
                                                    linked=linked)

    def createParametric(self, name):
        """Use a parametric form to create the dataset.

        Raises _DSException if error
        """
        t0 = float( unicode(self.tstartedit.text()) )
        t1 = float( unicode(self.tendedit.text()) )
        numsteps = int( unicode(self.tstepsedit.text()) )

        # get expressions
        vals = {}
        for key, cntrl in self.dsedits.iteritems():
            text = unicode( cntrl.text() ).strip()
            if text:
                vals[key] = text
           
        linked = self.linkcheckbox.checkState() == qt4.Qt.Checked
        return document.OperationDatasetCreateParameteric(name,
                                                          t0, t1, numsteps,
                                                          vals, linked=linked)
      
    def createFromExpression(self, name):
        """Create a dataset based on the expressions given."""

        # get expression for each part of the dataset
        vals = {}
        for key, cntrl in self.dsedits.iteritems():
            text = unicode( cntrl.text() ).strip()
            if text:
                vals[key] = text

        link = self.linkcheckbox.checkState() == qt4.Qt.Checked
        op = document.OperationDatasetCreateExpression(name, vals, link)
        op.validateExpression(self.document)
        return op

def recreateDataset(mainwindow, document, dataset, datasetname):
    """Open dialog to recreate a DatasetExpression / DatasetRange."""
    dialog = DataCreateDialog(mainwindow, document)
    mainwindow.showDialog(dialog)
    dialog.reEditDataset(dataset, datasetname)

dataeditdialog.recreate_register[document.DatasetExpression] = recreateDataset
dataeditdialog.recreate_register[document.DatasetRange] = recreateDataset