tools/designer/src/lib/shared/qdesigner_promotiondialog.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Designer of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qdesigner_promotiondialog_p.h"
       
    43 #include "promotionmodel_p.h"
       
    44 #include "iconloader_p.h"
       
    45 #include "widgetdatabase_p.h"
       
    46 #include "signalslotdialog_p.h"
       
    47 
       
    48 #include <QtDesigner/QDesignerFormEditorInterface>
       
    49 #include <QtDesigner/QDesignerFormWindowInterface>
       
    50 #include <QtDesigner/QDesignerPromotionInterface>
       
    51 #include <QtDesigner/QDesignerWidgetDataBaseItemInterface>
       
    52 #include <abstractdialoggui_p.h>
       
    53 
       
    54 #include <QtCore/QTimer>
       
    55 #include <QtGui/QVBoxLayout>
       
    56 #include <QtGui/QHBoxLayout>
       
    57 #include <QtGui/QFormLayout>
       
    58 #include <QtGui/QDialogButtonBox>
       
    59 #include <QtGui/QTreeView>
       
    60 #include <QtGui/QHeaderView>
       
    61 #include <QtGui/QPushButton>
       
    62 #include <QtGui/QItemSelectionModel>
       
    63 #include <QtGui/QItemSelection>
       
    64 #include <QtGui/QComboBox>
       
    65 #include <QtGui/QLineEdit>
       
    66 #include <QtGui/QCheckBox>
       
    67 #include <QtGui/QRegExpValidator>
       
    68 #include <QtGui/QLabel>
       
    69 #include <QtGui/QSpacerItem>
       
    70 #include <QtGui/QMenu>
       
    71 #include <QtGui/QAction>
       
    72 
       
    73 QT_BEGIN_NAMESPACE
       
    74 
       
    75 namespace qdesigner_internal {
       
    76     // PromotionParameters
       
    77     struct PromotionParameters {
       
    78         QString m_baseClass;
       
    79         QString m_className;
       
    80         QString m_includeFile;
       
    81     };
       
    82 
       
    83     //  NewPromotedClassPanel
       
    84     NewPromotedClassPanel::NewPromotedClassPanel(const QStringList &baseClasses,
       
    85                                                    int selectedBaseClass,
       
    86                                                    QWidget *parent) :
       
    87         QGroupBox(parent),
       
    88         m_baseClassCombo(new  QComboBox),
       
    89         m_classNameEdit(new QLineEdit),
       
    90         m_includeFileEdit(new QLineEdit),
       
    91         m_globalIncludeCheckBox(new QCheckBox),
       
    92         m_addButton(new QPushButton(tr("Add")))
       
    93     {
       
    94         setTitle(tr("New Promoted Class"));
       
    95         setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
       
    96         QHBoxLayout *hboxLayout = new QHBoxLayout(this);
       
    97 
       
    98         m_classNameEdit->setValidator(new QRegExpValidator(QRegExp(QLatin1String("[_a-zA-Z:][:_a-zA-Z0-9]*")), m_classNameEdit));
       
    99         connect(m_classNameEdit,   SIGNAL(textChanged(QString)), this, SLOT(slotNameChanged(QString)));
       
   100         connect(m_includeFileEdit, SIGNAL(textChanged(QString)), this, SLOT(slotIncludeFileChanged(QString)));
       
   101 
       
   102         m_baseClassCombo->setEditable(false);
       
   103         m_baseClassCombo->addItems(baseClasses);
       
   104         if (selectedBaseClass != -1)
       
   105             m_baseClassCombo->setCurrentIndex(selectedBaseClass);
       
   106 
       
   107         // Grid
       
   108         QFormLayout *formLayout = new QFormLayout();
       
   109         formLayout->addRow(tr("Base class name:"),     m_baseClassCombo);
       
   110         formLayout->addRow(tr("Promoted class name:"), m_classNameEdit);
       
   111         formLayout->addRow(tr("Header file:"),         m_includeFileEdit);
       
   112         formLayout->addRow(tr("Global include"),       m_globalIncludeCheckBox);
       
   113         hboxLayout->addLayout(formLayout);
       
   114         hboxLayout->addItem(new QSpacerItem(15, 0, QSizePolicy::Fixed, QSizePolicy::Ignored));
       
   115         // Button box
       
   116         QVBoxLayout *buttonLayout = new QVBoxLayout();
       
   117 
       
   118         m_addButton->setAutoDefault(false);
       
   119         connect(m_addButton, SIGNAL(clicked()), this, SLOT(slotAdd()));
       
   120         m_addButton->setEnabled(false);
       
   121         buttonLayout->addWidget(m_addButton);
       
   122 
       
   123         QPushButton *resetButton = new QPushButton(tr("Reset"));
       
   124         resetButton->setAutoDefault(false);
       
   125         connect(resetButton, SIGNAL(clicked()), this, SLOT(slotReset()));
       
   126 
       
   127         buttonLayout->addWidget(resetButton);
       
   128         buttonLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::Expanding));
       
   129         hboxLayout->addLayout(buttonLayout);
       
   130 
       
   131         enableButtons();
       
   132     }
       
   133 
       
   134     void NewPromotedClassPanel::slotAdd() {
       
   135         bool ok = false;
       
   136         emit newPromotedClass(promotionParameters(), &ok);
       
   137         if (ok)
       
   138             slotReset();
       
   139     }
       
   140 
       
   141     void NewPromotedClassPanel::slotReset() {
       
   142         const QString empty;
       
   143         m_classNameEdit->setText(empty);
       
   144         m_includeFileEdit->setText(empty);
       
   145         m_globalIncludeCheckBox->setCheckState(Qt::Unchecked);
       
   146     }
       
   147 
       
   148     void NewPromotedClassPanel::grabFocus() {
       
   149         m_classNameEdit->setFocus(Qt::OtherFocusReason);
       
   150     }
       
   151 
       
   152     void NewPromotedClassPanel::slotNameChanged(const QString &className) {
       
   153         // Suggest a name
       
   154         if (!className.isEmpty()) {
       
   155             QString suggestedHeader = className.toLower().replace(QLatin1String("::"), QString(QLatin1Char('_')));
       
   156             suggestedHeader += QLatin1String(".h");
       
   157 
       
   158             const bool blocked = m_includeFileEdit->blockSignals(true);
       
   159             m_includeFileEdit->setText(suggestedHeader);
       
   160             m_includeFileEdit->blockSignals(blocked);
       
   161         }
       
   162         enableButtons();
       
   163     }
       
   164 
       
   165     void NewPromotedClassPanel::slotIncludeFileChanged(const QString &){
       
   166         enableButtons();
       
   167     }
       
   168 
       
   169     void NewPromotedClassPanel::enableButtons() {
       
   170         const bool enabled = !m_classNameEdit->text().isEmpty() && !m_includeFileEdit->text().isEmpty();
       
   171         m_addButton->setEnabled(enabled);
       
   172         m_addButton->setDefault(enabled);
       
   173     }
       
   174 
       
   175     PromotionParameters NewPromotedClassPanel::promotionParameters() const {
       
   176          PromotionParameters rc;
       
   177          rc.m_baseClass = m_baseClassCombo->currentText();
       
   178          rc.m_className = m_classNameEdit->text();
       
   179          rc.m_includeFile = buildIncludeFile(m_includeFileEdit->text(),
       
   180                                              m_globalIncludeCheckBox->checkState() == Qt::Checked ? IncludeGlobal : IncludeLocal);
       
   181          return rc;
       
   182      }
       
   183 
       
   184     void NewPromotedClassPanel::chooseBaseClass(const QString &baseClass) {
       
   185         const int index = m_baseClassCombo->findText (baseClass);
       
   186         if (index != -1)
       
   187             m_baseClassCombo->setCurrentIndex (index);
       
   188     }
       
   189 
       
   190     // --------------- QDesignerPromotionDialog
       
   191     QDesignerPromotionDialog::QDesignerPromotionDialog(QDesignerFormEditorInterface *core,
       
   192                                                        QWidget *parent,
       
   193                                                        const QString &promotableWidgetClassName,
       
   194                                                        QString *promoteTo) :
       
   195         QDialog(parent),
       
   196         m_mode(promotableWidgetClassName.isEmpty() || promoteTo == 0 ? ModeEdit : ModeEditChooseClass),
       
   197         m_promotableWidgetClassName(promotableWidgetClassName),
       
   198         m_core(core),
       
   199         m_promoteTo(promoteTo),
       
   200         m_promotion(core->promotion()),
       
   201         m_model(new PromotionModel(core)),
       
   202         m_treeView(new QTreeView),
       
   203         m_buttonBox(0),
       
   204         m_removeButton(new QPushButton(createIconSet(QString::fromUtf8("minus.png")), QString()))
       
   205     {
       
   206         m_buttonBox = createButtonBox();
       
   207         setModal(true);
       
   208         setWindowTitle(tr("Promoted Widgets"));
       
   209         setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
       
   210 
       
   211         QVBoxLayout *vboxLayout = new QVBoxLayout(this);
       
   212 
       
   213         // tree view group
       
   214         QGroupBox *treeViewGroup = new QGroupBox();
       
   215         treeViewGroup->setTitle(tr("Promoted Classes"));
       
   216         QVBoxLayout *treeViewVBoxLayout = new QVBoxLayout(treeViewGroup);
       
   217         // tree view
       
   218         m_treeView->setModel (m_model);
       
   219         m_treeView->setMinimumWidth(450);
       
   220         m_treeView->setContextMenuPolicy(Qt::CustomContextMenu);
       
   221 
       
   222         connect(m_treeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
       
   223                 this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection)));
       
   224 
       
   225         connect(m_treeView, SIGNAL(customContextMenuRequested(QPoint)),
       
   226                 this, SLOT(slotTreeViewContextMenu(QPoint)));
       
   227 
       
   228         QHeaderView *headerView = m_treeView->header();
       
   229         headerView->setResizeMode(QHeaderView::ResizeToContents);
       
   230         treeViewVBoxLayout->addWidget(m_treeView);
       
   231         // remove button
       
   232         QHBoxLayout *hboxLayout = new QHBoxLayout();
       
   233         hboxLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
       
   234 
       
   235         m_removeButton->setAutoDefault(false);
       
   236         connect(m_removeButton, SIGNAL(clicked()), this, SLOT(slotRemove()));
       
   237         m_removeButton->setEnabled(false);
       
   238         hboxLayout->addWidget(m_removeButton);
       
   239         treeViewVBoxLayout->addLayout(hboxLayout);
       
   240         vboxLayout->addWidget(treeViewGroup);
       
   241         // Create new panel: Try to be smart and preselect a base class. Default to QFrame
       
   242         const QStringList &baseClassNameList = baseClassNames(m_promotion);
       
   243         int preselectedBaseClass = -1;
       
   244         if (m_mode == ModeEditChooseClass) {
       
   245             preselectedBaseClass = baseClassNameList.indexOf(m_promotableWidgetClassName);
       
   246         }
       
   247         if (preselectedBaseClass == -1)
       
   248             preselectedBaseClass = baseClassNameList.indexOf(QLatin1String("QFrame"));
       
   249 
       
   250         NewPromotedClassPanel *newPromotedClassPanel = new NewPromotedClassPanel(baseClassNameList, preselectedBaseClass);
       
   251         connect(newPromotedClassPanel, SIGNAL(newPromotedClass(PromotionParameters, bool *)), this, SLOT(slotNewPromotedClass(PromotionParameters, bool *)));
       
   252         connect(this, SIGNAL(selectedBaseClassChanged(QString)),
       
   253                 newPromotedClassPanel, SLOT(chooseBaseClass(QString)));
       
   254         vboxLayout->addWidget(newPromotedClassPanel);
       
   255         // button box
       
   256         vboxLayout->addWidget(m_buttonBox);
       
   257         // connect model
       
   258         connect(m_model, SIGNAL(includeFileChanged(QDesignerWidgetDataBaseItemInterface*, QString)),
       
   259                 this, SLOT(slotIncludeFileChanged(QDesignerWidgetDataBaseItemInterface*, QString)));
       
   260 
       
   261         connect(m_model, SIGNAL(classNameChanged(QDesignerWidgetDataBaseItemInterface*, QString)),
       
   262                 this, SLOT(slotClassNameChanged(QDesignerWidgetDataBaseItemInterface*, QString)));
       
   263 
       
   264         // focus
       
   265         if (m_mode == ModeEditChooseClass)
       
   266             newPromotedClassPanel->grabFocus();
       
   267 
       
   268         slotUpdateFromWidgetDatabase();
       
   269     }
       
   270 
       
   271     QDialogButtonBox *QDesignerPromotionDialog::createButtonBox() {
       
   272         QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Close);
       
   273 
       
   274         connect(buttonBox , SIGNAL(accepted()), this, SLOT(slotAcceptPromoteTo()));
       
   275         buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Promote"));
       
   276         buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
       
   277 
       
   278         connect(buttonBox , SIGNAL(rejected()), this, SLOT(reject()));
       
   279         return buttonBox;
       
   280     }
       
   281 
       
   282     void QDesignerPromotionDialog::slotUpdateFromWidgetDatabase() {
       
   283         m_model->updateFromWidgetDatabase();
       
   284         m_treeView->expandAll();
       
   285         m_removeButton->setEnabled(false);
       
   286     }
       
   287 
       
   288     void QDesignerPromotionDialog::delayedUpdateFromWidgetDatabase() {
       
   289         QTimer::singleShot(0, this, SLOT(slotUpdateFromWidgetDatabase()));
       
   290     }
       
   291 
       
   292     const QStringList &QDesignerPromotionDialog::baseClassNames(const QDesignerPromotionInterface *promotion) {
       
   293         typedef QList<QDesignerWidgetDataBaseItemInterface *> WidgetDataBaseItemList;
       
   294         static QStringList rc;
       
   295         if (rc.empty()) {
       
   296             // Convert the item list into a string list.
       
   297             const WidgetDataBaseItemList dbItems =  promotion->promotionBaseClasses();
       
   298             const WidgetDataBaseItemList::const_iterator cend =  dbItems.constEnd();
       
   299             for (WidgetDataBaseItemList::const_iterator it = dbItems.constBegin() ; it != cend; ++it) {
       
   300                 rc.push_back( (*it)->name());
       
   301             }
       
   302         }
       
   303         return rc;
       
   304     }
       
   305 
       
   306     void  QDesignerPromotionDialog::slotAcceptPromoteTo() {
       
   307         Q_ASSERT(m_mode == ModeEditChooseClass);
       
   308         unsigned flags;
       
   309         // Ok pressed: Promote to selected class
       
   310         if (QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(m_treeView->selectionModel()->selection(), flags)) {
       
   311             if (flags & CanPromote) {
       
   312                 *m_promoteTo = dbItem ->name();
       
   313                 accept();
       
   314             }
       
   315         }
       
   316     }
       
   317 
       
   318     void QDesignerPromotionDialog::slotRemove() {
       
   319         unsigned flags;
       
   320         QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(m_treeView->selectionModel()->selection(), flags);
       
   321         if (!dbItem || (flags & Referenced))
       
   322             return;
       
   323 
       
   324         QString errorMessage;
       
   325         if (m_promotion->removePromotedClass(dbItem->name(), &errorMessage)) {
       
   326             slotUpdateFromWidgetDatabase();
       
   327         } else {
       
   328             displayError(errorMessage);
       
   329         }
       
   330     }
       
   331 
       
   332     void QDesignerPromotionDialog::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &) {
       
   333         // Enable deleting non-referenced items
       
   334         unsigned flags;
       
   335         const QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(selected, flags);
       
   336         m_removeButton->setEnabled(dbItem && !(flags & Referenced));
       
   337         // In choose mode, can we promote to the class?
       
   338         if (m_mode == ModeEditChooseClass) {
       
   339             const bool enablePromoted = flags & CanPromote;
       
   340             m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(enablePromoted);
       
   341             m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(enablePromoted);
       
   342         }
       
   343         // different base?
       
   344         if (dbItem) {
       
   345             const QString baseClass = dbItem->extends();
       
   346             if (baseClass !=  m_lastSelectedBaseClass) {
       
   347                 m_lastSelectedBaseClass = baseClass;
       
   348                 emit selectedBaseClassChanged(m_lastSelectedBaseClass);
       
   349             }
       
   350         }
       
   351     }
       
   352 
       
   353     QDesignerWidgetDataBaseItemInterface *QDesignerPromotionDialog::databaseItemAt(const QItemSelection &selected, unsigned &flags) const {
       
   354         flags = 0;
       
   355         const QModelIndexList indexes = selected.indexes();
       
   356         if (indexes.empty())
       
   357             return 0;
       
   358 
       
   359         bool referenced;
       
   360         QDesignerWidgetDataBaseItemInterface *dbItem = m_model->databaseItemAt(indexes.front(), &referenced);
       
   361 
       
   362         if (dbItem) {
       
   363             if (referenced)
       
   364                 flags |= Referenced;
       
   365             // In choose mode, can we promote to the class?
       
   366             if (m_mode == ModeEditChooseClass &&  dbItem && dbItem->isPromoted() && dbItem->extends() ==  m_promotableWidgetClassName)
       
   367                 flags |= CanPromote;
       
   368 
       
   369         }
       
   370         return dbItem;
       
   371     }
       
   372 
       
   373     void QDesignerPromotionDialog::slotNewPromotedClass(const PromotionParameters &p, bool *ok) {
       
   374         QString  errorMessage;
       
   375         *ok = m_promotion->addPromotedClass(p.m_baseClass, p.m_className, p.m_includeFile, &errorMessage);
       
   376         if (*ok) {
       
   377             // update and select
       
   378             slotUpdateFromWidgetDatabase();
       
   379             const QModelIndex newClassIndex = m_model->indexOfClass(p.m_className);
       
   380             if (newClassIndex.isValid()) {
       
   381                 m_treeView->selectionModel()->select(newClassIndex, QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows);
       
   382             }
       
   383         } else {
       
   384             displayError(errorMessage);
       
   385         }
       
   386     }
       
   387 
       
   388     void QDesignerPromotionDialog::slotIncludeFileChanged(QDesignerWidgetDataBaseItemInterface *dbItem, const QString &includeFile) {
       
   389         if (includeFile.isEmpty()) {
       
   390             delayedUpdateFromWidgetDatabase();
       
   391             return;
       
   392         }
       
   393 
       
   394         if (dbItem->includeFile() == includeFile)
       
   395             return;
       
   396 
       
   397         QString errorMessage;
       
   398         if (!m_promotion->setPromotedClassIncludeFile(dbItem->name(), includeFile, &errorMessage)) {
       
   399             displayError(errorMessage);
       
   400             delayedUpdateFromWidgetDatabase();
       
   401         }
       
   402     }
       
   403 
       
   404     void  QDesignerPromotionDialog::slotClassNameChanged(QDesignerWidgetDataBaseItemInterface *dbItem, const QString &newName) {
       
   405         if (newName.isEmpty()) {
       
   406             delayedUpdateFromWidgetDatabase();
       
   407             return;
       
   408         }
       
   409         const QString oldName = dbItem->name();
       
   410         if (newName == oldName)
       
   411             return;
       
   412 
       
   413         QString errorMessage;
       
   414         if (!m_promotion->changePromotedClassName(oldName , newName, &errorMessage)) {
       
   415             displayError(errorMessage);
       
   416             delayedUpdateFromWidgetDatabase();
       
   417         }
       
   418     }
       
   419 
       
   420     void QDesignerPromotionDialog::slotTreeViewContextMenu(const QPoint &pos) {
       
   421         unsigned flags;
       
   422         const QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(m_treeView->selectionModel()->selection(), flags);
       
   423         if (!dbItem)
       
   424             return;
       
   425 
       
   426         QMenu menu;
       
   427         QAction *signalSlotAction = menu.addAction(tr("Change signals/slots..."));
       
   428         connect(signalSlotAction, SIGNAL(triggered()), this, SLOT(slotEditSignalsSlots()));
       
   429 
       
   430         menu.exec(m_treeView->viewport()->mapToGlobal(pos));
       
   431     }
       
   432 
       
   433     void  QDesignerPromotionDialog::slotEditSignalsSlots() {
       
   434         unsigned flags;
       
   435         const QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(m_treeView->selectionModel()->selection(), flags);
       
   436         if (!dbItem)
       
   437             return;
       
   438 
       
   439         SignalSlotDialog::editPromotedClass(m_core, dbItem->name(), this);
       
   440     }
       
   441 
       
   442     void QDesignerPromotionDialog::displayError(const QString &message) {
       
   443         m_core->dialogGui()->message(this, QDesignerDialogGuiInterface::PromotionErrorMessage, QMessageBox::Warning,
       
   444                                      tr("%1 - Error").arg(windowTitle()), message,  QMessageBox::Close);
       
   445     }
       
   446 } // namespace qdesigner_internal
       
   447 
       
   448 QT_END_NAMESPACE