umloperationdialog.cpp 16.1 KB
Newer Older
1
2
3
4
5
6
/***************************************************************************
 *   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.                                   *
 *                                                                         *
Oliver Kellogg's avatar
Oliver Kellogg committed
7
 *   copyright (C) 2002-2014                                               *
Ralf Habacker's avatar
Ralf Habacker committed
8
 *   Umbrello UML Modeller Authors <umbrello-devel@kde.org>                *
9
10
 ***************************************************************************/

11
12
13
// own header
#include "umloperationdialog.h"

14
//app includes
15
#include "debug_utils.h"
16
17
18
19
20
#include "uml.h"
#include "umldoc.h"
#include "operation.h"
#include "classifier.h"
#include "template.h"
21
#include "dialogspopupmenu.h"
22
#include "umlattributelist.h"
23
#include "umldatatypewidget.h"
24
#include "umlstereotypewidget.h"
25
#include "classifierlistitem.h"
26
#include "documentationwidget.h"
27
28
#include "umlclassifierlistitemlist.h"
#include "dialog_utils.h"
29
#include "parameterpropertiesdialog.h"
30
31
#include "stereotype.h"
#include "uniqueid.h"
32
#include "visibilityenumwidget.h"
33

34
//kde includes
35
36
37
#if QT_VERSION < 0x050000
#include <kdialogbuttonbox.h>
#endif
38
39
#include <klineedit.h>
#include <kcombobox.h>
40
#include <KLocalizedString>
41
#include <KMessageBox>
42
43

//qt includes
44
45
46
47
48
49
50
51
52
53
54
55
#include <QCheckBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QLayout>
#include <QListWidget>
#include <QPointer>
#include <QPushButton>
#include <QRadioButton>
#include <QToolButton>
#include <QVBoxLayout>
56

57
58
59
/**
 * Constructor.
 */
60
UMLOperationDialog::UMLOperationDialog(QWidget * parent, UMLOperation * pOperation)
61
62
  : SinglePageDialogBase(parent),
    m_pOverrideCB(0)
63
{
64
    setCaption(i18n("Operation Properties"));
65
    m_operation = pOperation;
66
    m_doc = UMLApp::app()->document();
67
    m_menu = 0;
Oliver Kellogg's avatar
Oliver Kellogg committed
68
    setupDialog();
69
70
}

71
72
73
/**
 * Destructor.
 */
74
75
76
UMLOperationDialog::~UMLOperationDialog()
{
}
77

78
79
80
/**
 * Sets up the dialog.
 */
81
82
void UMLOperationDialog::setupDialog()
{
83
84
    QFrame *frame = new QFrame(this);
    setMainWidget(frame);
Oliver Kellogg's avatar
Oliver Kellogg committed
85
    int margin = fontMetrics().height();
86
    QVBoxLayout * topLayout = new QVBoxLayout(frame);
Oliver Kellogg's avatar
Oliver Kellogg committed
87

88
    m_pGenGB = new QGroupBox(i18n("General Properties"), frame);
Stephan Kulow's avatar
Stephan Kulow committed
89
    QGridLayout * genLayout = new QGridLayout(m_pGenGB);
90
91
92
93
94
95
    genLayout->setColumnStretch(1, 1);
    genLayout->setColumnStretch(3, 1);
    genLayout->addItem(new QSpacerItem(200, 0), 0, 1);
    genLayout->addItem(new QSpacerItem(200, 0), 0, 3);
    genLayout->setMargin(margin);
    genLayout->setSpacing(10);
Oliver Kellogg's avatar
Oliver Kellogg committed
96

97
    Dialog_Utils::makeLabeledEditField(genLayout, 0,
98
                                    m_pNameL, i18nc("operation name", "&Name:"),
99
                                    m_pNameLE, m_operation->name());
Oliver Kellogg's avatar
Oliver Kellogg committed
100

101
102
    m_datatypeWidget = new UMLDatatypeWidget(m_operation);
    m_datatypeWidget->addToLayout(genLayout, 0, 2);
Oliver Kellogg's avatar
Oliver Kellogg committed
103

104
105
    m_stereotypeWidget = new UMLStereotypeWidget(m_operation);
    m_stereotypeWidget->addToLayout(genLayout, 1);
Oliver Kellogg's avatar
Oliver Kellogg committed
106

107
    bool isInterface = m_operation->umlPackage()->asUMLClassifier()->isInterface();
108
109
    m_pAbstractCB = new QCheckBox(i18n("&Abstract operation"), m_pGenGB);
    m_pAbstractCB->setChecked(m_operation->isAbstract());
110
    m_pAbstractCB->setEnabled(!isInterface);
111
112
113
114
115
116
117
    genLayout->addWidget(m_pAbstractCB, 2, 0);
    m_pStaticCB = new QCheckBox(i18n("Classifier &scope (\"static\")"), m_pGenGB);
    m_pStaticCB->setChecked(m_operation->isStatic());
    genLayout->addWidget(m_pStaticCB, 2, 1);
    m_pQueryCB = new QCheckBox(i18n("&Query (\"const\")"), m_pGenGB);
    m_pQueryCB->setChecked(m_operation->getConst());
    genLayout->addWidget(m_pQueryCB, 2, 2);
118
119
    m_virtualCB = new QCheckBox(i18n("&virtual"), m_pGenGB);
    m_virtualCB->setChecked(m_operation->isVirtual());
120
    m_virtualCB->setEnabled(!isInterface);
121
    genLayout->addWidget(m_virtualCB, 2, 3);
122
123
    m_inlineCB = new QCheckBox(i18n("&inline"), m_pGenGB);
    m_inlineCB->setChecked(m_operation->isInline());
124
    m_inlineCB->setEnabled(!isInterface);
125
    genLayout->addWidget(m_inlineCB, 2, 4);
126
127
128
    if (Settings::optionState().codeImportState.supportCPP11) {
        m_pOverrideCB = new QCheckBox(i18n("&Override"), m_pGenGB);
        m_pOverrideCB->setChecked(m_operation->getOverride());
129
        m_pOverrideCB->setEnabled(!isInterface);
130
        genLayout->addWidget(m_pOverrideCB, 2, 5);
131
    }
Oliver Kellogg's avatar
Oliver Kellogg committed
132

133
    m_visibilityEnumWidget = new VisibilityEnumWidget(m_operation, this);
134
    m_visibilityEnumWidget->setEnabled(!isInterface);
Oliver Kellogg's avatar
Oliver Kellogg committed
135

136
137
    m_docWidget = new DocumentationWidget(m_operation, this);

138
    m_pParmsGB = new QGroupBox(i18n("Parameters"), frame);
Oliver Kellogg's avatar
Oliver Kellogg committed
139
140
141
142
    QVBoxLayout* parmsLayout = new QVBoxLayout(m_pParmsGB);
    parmsLayout->setMargin(margin);
    parmsLayout->setSpacing(10);

143
144
145
146
    // horizontal box contains the list box and the move up/down buttons
    QHBoxLayout* parmsHBoxLayout = new QHBoxLayout();
    m_pParmsLW = new QListWidget(m_pParmsGB);
    m_pParmsLW->setContextMenuPolicy(Qt::CustomContextMenu);
Oliver Kellogg's avatar
Oliver Kellogg committed
147

148
149
    // the move up/down buttons (another vertical box)
    QVBoxLayout* buttonLayout = new QVBoxLayout();
Oliver Kellogg's avatar
Oliver Kellogg committed
150

151
152
153
154
155
156
157
158
159
    m_pUpButton = new QToolButton(m_pParmsGB);
    m_pUpButton->setArrowType(Qt::UpArrow);
    m_pUpButton->setEnabled(false);
    buttonLayout->addWidget(m_pUpButton);

    m_pDownButton = new QToolButton(m_pParmsGB);
    m_pDownButton->setArrowType(Qt::DownArrow);
    m_pDownButton->setEnabled(false);
    buttonLayout->addWidget(m_pDownButton);
Oliver Kellogg's avatar
Oliver Kellogg committed
160

161
162
163
164
165
166
167
168
169
#if QT_VERSION >= 0x050000
    QDialogButtonBox* buttonBox = new QDialogButtonBox(m_pParmsGB);
    QPushButton* newParam = buttonBox->addButton(i18n("Ne&w Parameter..."), QDialogButtonBox::ActionRole);
    connect(newParam, SIGNAL(clicked()), this, SLOT(slotNewParameter()));
    m_pDeleteButton = buttonBox->addButton(i18n("&Delete"), QDialogButtonBox::ActionRole);
    connect(m_pDeleteButton, SIGNAL(clicked()), this, SLOT(slotDeleteParameter()));
    m_pPropertiesButton = buttonBox->addButton(i18n("&Properties"), QDialogButtonBox::ActionRole);
    connect(m_pPropertiesButton, SIGNAL(clicked()), this, SLOT(slotParameterProperties()));
#else
Urs Wolfer's avatar
Urs Wolfer committed
170
    KDialogButtonBox* buttonBox = new KDialogButtonBox(m_pParmsGB);
171
172
173
174
175
176
    buttonBox->addButton(i18n("Ne&w Parameter..."), KDialogButtonBox::ActionRole,
                          this, SLOT(slotNewParameter()));
    m_pDeleteButton = buttonBox->addButton(i18n("&Delete"), KDialogButtonBox::ActionRole,
                                            this, SLOT(slotDeleteParameter()));
    m_pPropertiesButton = buttonBox->addButton(i18n("&Properties"), KDialogButtonBox::ActionRole,
                          this, SLOT(slotParameterProperties()));
177
#endif
178
179
180
181
182

    parmsHBoxLayout->addWidget(m_pParmsLW);
    parmsHBoxLayout->addLayout(buttonLayout);

    parmsLayout->addLayout(parmsHBoxLayout);
Oliver Kellogg's avatar
Oliver Kellogg committed
183
184
    parmsLayout->addWidget(buttonBox);

185
    topLayout->addWidget(m_pGenGB);
186
    topLayout->addWidget(m_visibilityEnumWidget);
187
    topLayout->addWidget(m_docWidget);
188
    topLayout->addWidget(m_pParmsGB);
Oliver Kellogg's avatar
Oliver Kellogg committed
189
190
191
192
193
194

    m_pDeleteButton->setEnabled(false);
    m_pPropertiesButton->setEnabled(false);
    m_pUpButton->setEnabled(false);
    m_pDownButton->setEnabled(false);

195
196
    // fill in parm list box
    UMLAttributeList list = m_operation->getParmList();
197
198
    foreach (UMLAttribute* pAtt, list) {
        m_pParmsLW->addItem(pAtt->toString(Uml::SignatureType::SigNoVis));
Sharan Rao's avatar
Sharan Rao committed
199
    }
Oliver Kellogg's avatar
Oliver Kellogg committed
200

201
    // setup parm list box signals
202
203
    connect(m_pUpButton, SIGNAL(clicked()), this, SLOT(slotParameterUp()));
    connect(m_pDownButton, SIGNAL(clicked()), this, SLOT(slotParameterDown()));
Oliver Kellogg's avatar
Oliver Kellogg committed
204

205
206
    connect(m_pParmsLW, SIGNAL(itemClicked(QListWidgetItem*)),
            this, SLOT(slotParamsBoxClicked(QListWidgetItem*)));
207
208
209
210
    connect(m_pParmsLW, SIGNAL(customContextMenuRequested(QPoint)),
            this, SLOT(slotParmRightButtonPressed(QPoint)));
    connect(m_pParmsLW, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
            this, SLOT(slotParmDoubleClick(QListWidgetItem*)));
Oliver Kellogg's avatar
Oliver Kellogg committed
211
212

    m_pNameLE->setFocus();
213
214
    connect(m_pNameLE, SIGNAL(textChanged(QString)), SLOT(slotNameChanged(QString)));
    slotNameChanged(m_pNameLE->text());
215
216
}

217
void UMLOperationDialog::slotNameChanged(const QString &_text)
218
{
219
    enableButtonOk(!_text.isEmpty());
220
221
}

222
void UMLOperationDialog::slotParmRightButtonPressed(const QPoint &p)
223
{
224
    DialogsPopupMenu::TriggerType type = DialogsPopupMenu::tt_Undefined;
225
226
    QListWidgetItem* item = m_pParmsLW->itemAt(p);
    if (item) // pressed on an item
Oliver Kellogg's avatar
Oliver Kellogg committed
227
    {
228
        type = DialogsPopupMenu::tt_Parameter_Selected;
229
    } else // pressed into fresh air
Oliver Kellogg's avatar
Oliver Kellogg committed
230
    {
231
        type = DialogsPopupMenu::tt_New_Parameter;
Oliver Kellogg's avatar
Oliver Kellogg committed
232
    }
233
    if (m_menu) {
234
        m_menu->hide();
235
        disconnect(m_menu, SIGNAL(triggered(QAction*)), this, SLOT(slotMenuSelection(QAction*)));
236
237
        delete m_menu;
        m_menu = 0;
Oliver Kellogg's avatar
Oliver Kellogg committed
238
    }
239
    DialogsPopupMenu popup(this, type);
240
241
    QAction *triggered = popup.exec(m_pParmsLW->mapToGlobal(p));
    slotMenuSelection(triggered);
242
243
}

244
void UMLOperationDialog::slotParmDoubleClick(QListWidgetItem *item)
245
{
246
    if (!item) {
Oliver Kellogg's avatar
Oliver Kellogg committed
247
        return;
248
    }
249
    // this happens, when there was no right click in the list widget
250
251
    DialogsPopupMenu popup(this, DialogsPopupMenu::tt_Parameter_Selected);
    QAction *triggered = popup.getAction(DialogsPopupMenu::mt_Properties);
252
    slotMenuSelection(triggered);
253
254
}

255
void UMLOperationDialog::slotMenuSelection(QAction* action)
256
{
257
258
    DialogsPopupMenu::MenuType id = DialogsPopupMenu::typeFromAction(action);
    if(id == DialogsPopupMenu::mt_Rename || id == DialogsPopupMenu::mt_Properties) {
Oliver Kellogg's avatar
Oliver Kellogg committed
259
        slotParameterProperties();
260
    } else if(id == DialogsPopupMenu::mt_New_Parameter) {
Oliver Kellogg's avatar
Oliver Kellogg committed
261
262
        slotNewParameter();
    }
263
    else if(id == DialogsPopupMenu::mt_Delete) {
Oliver Kellogg's avatar
Oliver Kellogg committed
264
265
        slotDeleteParameter();
    }
266
267
}

268
269
void UMLOperationDialog::slotNewParameter()
{
Oliver Kellogg's avatar
Oliver Kellogg committed
270
271
    UMLAttribute* pAtt = 0;

272
    QString currentName = m_operation->getUniqueParameterName();
Andi Fischer's avatar
Andi Fischer committed
273
    UMLAttribute* newAttribute = new UMLAttribute(m_operation, currentName, Uml::ID::Reserved);
Oliver Kellogg's avatar
Oliver Kellogg committed
274

275
    QPointer<ParameterPropertiesDialog> dlg = new ParameterPropertiesDialog(this, m_doc, newAttribute);
276
277
278
279
280
281
282
283
    if (dlg->exec()) {
        pAtt = m_operation->findParm(newAttribute->name());

        if (!pAtt) {
            newAttribute->setID(UniqueID::gen());
            m_operation->addParm(newAttribute);
            m_pParmsLW->addItem(newAttribute->toString(Uml::SignatureType::SigNoVis));
            m_doc->setModified(true);
Oliver Kellogg's avatar
Oliver Kellogg committed
284
285
        } else {
            KMessageBox::sorry(this, i18n("The parameter name you have chosen\nis already being used in this operation."),
Laurent Montel's avatar
Laurent Montel committed
286
                               i18n("Parameter Name Not Unique"), 0);
Oliver Kellogg's avatar
Oliver Kellogg committed
287
288
289
290
291
            delete newAttribute;
        }
    } else {
        delete newAttribute;
    }
292
    delete dlg;
293
294
}

295
296
void UMLOperationDialog::slotDeleteParameter()
{
297
    UMLAttribute* pOldAtt = m_operation->getParmList().at(m_pParmsLW->row(m_pParmsLW->currentItem()));
298

299
300
    m_operation->removeParm(pOldAtt);
    m_pParmsLW->takeItem(m_pParmsLW->currentRow());
Oliver Kellogg's avatar
Oliver Kellogg committed
301
    m_doc->setModified(true);
302

Oliver Kellogg's avatar
Oliver Kellogg committed
303
304
305
306
    m_pDeleteButton->setEnabled(false);
    m_pPropertiesButton->setEnabled(false);
    m_pUpButton->setEnabled(false);
    m_pDownButton->setEnabled(false);
307
308
}

309
310
void UMLOperationDialog::slotParameterProperties()
{
Oliver Kellogg's avatar
Oliver Kellogg committed
311
312
    UMLAttribute* pAtt = 0, * pOldAtt = 0;

313
314
315
    int position = m_pParmsLW->row(m_pParmsLW->currentItem());
    pOldAtt = m_operation->getParmList().at(position);
    if (!pOldAtt) {
316
        uDebug() << "THE impossible has occurred for:" << m_pParmsLW->currentItem()->text();
Oliver Kellogg's avatar
Oliver Kellogg committed
317
        return;
318
    } // should never occur
319

320
    QString oldAttName = pOldAtt->name();
321
    UMLAttribute* tempAttribute = pOldAtt->clone()->asUMLAttribute(); // create a clone of the parameter
322

323
    // send the clone to the properties dialog box. it will fill in the new parameters.
324
    QPointer<ParameterPropertiesDialog> dlg = new ParameterPropertiesDialog(this, m_doc, tempAttribute);
325
    if (dlg->exec()) {
326
        bool namingConflict = false;
327
        QString newName = tempAttribute->name();
328

329
        pAtt = m_operation->findParm(newName); // search whether a parameter with this name already exists
330
        if(pAtt && pAtt != pOldAtt) {
Oliver Kellogg's avatar
Oliver Kellogg committed
331
            KMessageBox::error(this, i18n("The parameter name you have chosen is already being used in this operation."),
Laurent Montel's avatar
Laurent Montel committed
332
                               i18n("Parameter Name Not Unique"), 0);
333
            namingConflict = true;
Oliver Kellogg's avatar
Oliver Kellogg committed
334
        }
335

336
337
338
        tempAttribute->copyInto(pOldAtt); // copy all attributes from the clone
        if (namingConflict) {
            pOldAtt->setName(oldAttName); // reset the name if there was a naming conflict
339
340
341
        }

        QListWidgetItem* item = m_pParmsLW->currentItem();
342
343
        item->setText(pOldAtt->toString(Uml::SignatureType::SigNoVis));
        m_doc->setModified(true);
Oliver Kellogg's avatar
Oliver Kellogg committed
344
    }
345
    delete tempAttribute;
346
    delete dlg;
347
348
}

349
350
void UMLOperationDialog::slotParameterUp()
{
351
352
353
    int row = m_pParmsLW->currentRow();
    QListWidgetItem* item = m_pParmsLW->currentItem();
    if (item) {
354
        UMLAttribute* pOldAtt = m_operation->getParmList().at(m_pParmsLW->row(item));
Oliver Kellogg's avatar
Oliver Kellogg committed
355

356
        m_operation->moveParmLeft(pOldAtt);
357
358
359
360
361
362
363
364
365
        m_pParmsLW->takeItem(row);
        m_pParmsLW->insertItem(row - 1, item);

        m_doc->setModified(true);
        slotParamsBoxClicked(item);
    }
    else {
        uDebug() << "No current item in list widget!?";
    }
366
367
368
369
}

void UMLOperationDialog::slotParameterDown()
{
370
371
372
    int row = m_pParmsLW->currentRow();
    QListWidgetItem* item = m_pParmsLW->currentItem();
    if (item) {
373
        UMLAttribute* pOldAtt = m_operation->getParmList().at(m_pParmsLW->row(item));
374

375
        m_operation->moveParmRight(pOldAtt);
376
377
        m_pParmsLW->takeItem(row);
        m_pParmsLW->insertItem(row + 1, item);
378

379
380
381
382
383
384
        m_doc->setModified(true);
        slotParamsBoxClicked(item);
    }
    else {
        uDebug() << "No current item in list widget!?";
    }
385
386
}

387
388
389
/**
 * Enables or disables buttons.
 */
390
void UMLOperationDialog::slotParamsBoxClicked(QListWidgetItem* parameterItem)
391
{
Oliver Kellogg's avatar
Oliver Kellogg committed
392
393
394
    if (parameterItem) {
        m_pDeleteButton->setEnabled(true);
        m_pPropertiesButton->setEnabled(true);
395
396
397
398
399
        int row = m_pParmsLW->row(parameterItem);
        bool hasNext = (row < m_pParmsLW->count() - 1);
        bool hasPrev = (row > 0);
        m_pUpButton->setEnabled(hasPrev);
        m_pDownButton->setEnabled(hasNext);
Oliver Kellogg's avatar
Oliver Kellogg committed
400
401
402
403
404
405
    } else {
        m_pDeleteButton->setEnabled(false);
        m_pPropertiesButton->setEnabled(false);
        m_pUpButton->setEnabled(false);
        m_pDownButton->setEnabled(false);
    }
406
407
}

408
409
410
411
/**
 * Checks if changes are valid and applies them if they are,
 * else returns false.
 */
412
bool UMLOperationDialog::apply()
413
{
414
    QString name = m_pNameLE->text();
415
    if(name.length() == 0) {
Oliver Kellogg's avatar
Oliver Kellogg committed
416
        KMessageBox::error(this, i18n("You have entered an invalid operation name."),
Laurent Montel's avatar
Laurent Montel committed
417
                           i18n("Operation Name Invalid"), 0);
418
        m_pNameLE->setText(m_operation->name());
Oliver Kellogg's avatar
Oliver Kellogg committed
419
420
421
        return false;
    }

422
    UMLClassifier *classifier = m_operation->umlParent()->asUMLClassifier();
423
424
    if(classifier != 0 &&
            classifier->checkOperationSignature(name, m_operation->getParmList(), m_operation))
Oliver Kellogg's avatar
Oliver Kellogg committed
425
    {
426
        QString msg = i18n("An operation with that signature already exists in %1.\n", classifier->name())
Oliver Kellogg's avatar
Oliver Kellogg committed
427
                      +
428
                      i18n("Choose a different name or parameter list.");
Laurent Montel's avatar
Laurent Montel committed
429
        KMessageBox::error(this, msg, i18n("Operation Name Invalid"), 0);
Oliver Kellogg's avatar
Oliver Kellogg committed
430
431
        return false;
    }
432
    m_operation->setName(name);
Oliver Kellogg's avatar
Oliver Kellogg committed
433

434
    m_visibilityEnumWidget->apply();
435
    m_datatypeWidget->apply();
436
    m_stereotypeWidget->apply();
437

Oliver Kellogg's avatar
Oliver Kellogg committed
438
    bool isAbstract = m_pAbstractCB->isChecked();
439
    m_operation->setAbstract(isAbstract);
Oliver Kellogg's avatar
Oliver Kellogg committed
440
441
442
443
444
445
    if (isAbstract) {
        /* If any operation is abstract then the owning class needs
           to be made abstract.
           The inverse is not true: The fact that no operation is
           abstract does not mean that the class must be non-abstract.
         */
446
447
448
        if (classifier) {
            classifier->setAbstract(true);
        }
Oliver Kellogg's avatar
Oliver Kellogg committed
449
    }
450
451
    m_operation->setStatic(m_pStaticCB->isChecked());
    m_operation->setConst(m_pQueryCB->isChecked());
452
    m_operation->setVirtual(m_virtualCB->isChecked());
453
    m_operation->setInline(m_inlineCB->isChecked());
454
455
    if (m_pOverrideCB)
        m_operation->setOverride(m_pOverrideCB->isChecked());
456
    m_docWidget->apply();
Oliver Kellogg's avatar
Oliver Kellogg committed
457
458

    return true;
459
460
}

461