1 // Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESHGUI : GUI for SMESH component
24 // File : SMESHGUI_DuplicateNodesDlg.cxx
25 // Author : Michael ZORIN, Open CASCADE S.A.S.
28 #include "SMESHGUI_DuplicateNodesDlg.h"
31 #include "SMESHGUI_Utils.h"
32 #include "SMESHGUI_VTKUtils.h"
34 #include <SMESH_TypeFilter.hxx>
36 // SALOME GUI includes
37 #include <SUIT_Session.h>
38 #include <SUIT_ResourceMgr.h>
39 #include <SUIT_Desktop.h>
40 #include <SUIT_MessageBox.h>
41 #include <SUIT_OverrideCursor.h>
43 #include <LightApp_Application.h>
44 #include <LightApp_SelectionMgr.h>
46 #include <SalomeApp_Tools.h>
48 #include <SVTK_ViewWindow.h>
49 #include <SALOME_ListIO.hxx>
50 #include <SALOME_ListIteratorOfListIO.hxx>
53 #include <QApplication>
54 #include <QButtonGroup>
58 #include <QPushButton>
59 #include <QRadioButton>
61 #include <QHBoxLayout>
62 #include <QVBoxLayout>
65 #include <utilities.h>
68 #include <SALOMEconfig.h>
69 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
76 \brief Simple 'busy state' flag locker.
83 //! Constructor. Sets passed boolean flag to \c true.
84 BusyLocker( bool& busy ) : myBusy( busy ) { myBusy = true; }
85 //! Destructor. Clear external boolean flag passed as parameter to the constructor to \c false.
86 ~BusyLocker() { myBusy = false; }
88 bool& myBusy; //! External 'busy state' boolean flag
93 \param theModule Mesh module instance
95 SMESHGUI_DuplicateNodesDlg::SMESHGUI_DuplicateNodesDlg( SMESHGUI* theModule )
96 : QDialog( SMESH::GetDesktop( theModule ) ),
97 mySMESHGUI( theModule ),
98 mySelectionMgr( SMESH::GetSelectionMgr( theModule ) )
102 setAttribute(Qt::WA_DeleteOnClose, true);
103 setWindowTitle(tr("SMESH_DUPLICATE_TITLE"));
104 setSizeGripEnabled(true);
106 // Icons for the dialog operation modes and selection button
107 SUIT_ResourceMgr* aResMgr = SMESH::GetResourceMgr( mySMESHGUI );
108 QPixmap iconWithoutElem (aResMgr->loadPixmap("SMESH", tr("ICON_SMESH_DUPLICATE_NODES")));
109 QPixmap iconWithElem (aResMgr->loadPixmap("SMESH", tr("ICON_SMESH_DUPLICATE_NODES_WITH_ELEM")));
110 QPixmap iconSelect (aResMgr->loadPixmap("SMESH", tr("ICON_SELECT")));
113 QVBoxLayout* aMainLayout = new QVBoxLayout(this);
114 aMainLayout->setSpacing(SPACING);
115 aMainLayout->setMargin(MARGIN);
117 // Operation modes selector
118 QGroupBox* aConstructorsBox = new QGroupBox(tr("DUPLICATION_MODE"), this);
119 myGroupConstructors = new QButtonGroup(this);
120 QHBoxLayout* aConstructorsBoxLayout = new QHBoxLayout(aConstructorsBox);
121 aConstructorsBoxLayout->setSpacing(SPACING);
122 aConstructorsBoxLayout->setMargin(MARGIN);
124 QRadioButton* aRadioButton1 = new QRadioButton(aConstructorsBox);
125 aRadioButton1->setIcon(iconWithoutElem);
126 QRadioButton* aRadioButton2 = new QRadioButton(aConstructorsBox);
127 aRadioButton2->setIcon(iconWithElem);
129 aConstructorsBoxLayout->addWidget(aRadioButton1);
130 aConstructorsBoxLayout->addWidget(aRadioButton2);
131 myGroupConstructors->addButton(aRadioButton1, 0);
132 myGroupConstructors->addButton(aRadioButton2, 1);
135 myGroupArguments = new QGroupBox(this);
136 QGridLayout* aGroupArgumentsLayout = new QGridLayout(myGroupArguments);
137 aGroupArgumentsLayout->setSpacing(SPACING);
138 aGroupArgumentsLayout->setMargin(MARGIN);
140 myTextLabel1 = new QLabel(myGroupArguments);
141 mySelectButton1 = new QPushButton(myGroupArguments);
142 mySelectButton1->setIcon(iconSelect);
143 myLineEdit1 = new QLineEdit(myGroupArguments);
144 myLineEdit1->setReadOnly(true);
146 myTextLabel2 = new QLabel(myGroupArguments);
147 mySelectButton2 = new QPushButton(myGroupArguments);
148 mySelectButton2->setIcon(iconSelect);
149 myLineEdit2 = new QLineEdit(myGroupArguments);
150 myLineEdit2->setReadOnly(true);
152 myTextLabel3 = new QLabel(myGroupArguments);
153 mySelectButton3 = new QPushButton(myGroupArguments);
154 mySelectButton3->setIcon(iconSelect);
155 myLineEdit3 = new QLineEdit(myGroupArguments);
156 myLineEdit3->setReadOnly(true);
158 myCheckBoxNewElemGroup = new QCheckBox(tr("CONSTRUCT_NEW_GROUP_ELEMENTS"), myGroupArguments);
159 myCheckBoxNewNodeGroup = new QCheckBox(tr("CONSTRUCT_NEW_GROUP_NODES"), myGroupArguments);
161 aGroupArgumentsLayout->addWidget(myTextLabel1, 0, 0);
162 aGroupArgumentsLayout->addWidget(mySelectButton1, 0, 1);
163 aGroupArgumentsLayout->addWidget(myLineEdit1, 0, 2);
164 aGroupArgumentsLayout->addWidget(myTextLabel2, 1, 0);
165 aGroupArgumentsLayout->addWidget(mySelectButton2, 1, 1);
166 aGroupArgumentsLayout->addWidget(myLineEdit2, 1, 2);
167 aGroupArgumentsLayout->addWidget(myTextLabel3, 2, 0);
168 aGroupArgumentsLayout->addWidget(mySelectButton3, 2, 1);
169 aGroupArgumentsLayout->addWidget(myLineEdit3, 2, 2);
170 aGroupArgumentsLayout->addWidget(myCheckBoxNewElemGroup, 3, 0);
171 aGroupArgumentsLayout->addWidget(myCheckBoxNewNodeGroup, 4, 0);
172 aGroupArgumentsLayout->setRowStretch(5, 1);
175 QGroupBox* aGroupButtons = new QGroupBox(this);
176 QHBoxLayout* aGroupButtonsLayout = new QHBoxLayout(aGroupButtons);
177 aGroupButtonsLayout->setSpacing(SPACING);
178 aGroupButtonsLayout->setMargin(MARGIN);
180 myButtonOk = new QPushButton(tr("SMESH_BUT_APPLY_AND_CLOSE"), aGroupButtons);
181 myButtonOk->setAutoDefault(true);
182 myButtonOk->setDefault(true);
183 myButtonApply = new QPushButton(tr("SMESH_BUT_APPLY"), aGroupButtons);
184 myButtonApply->setAutoDefault(true);
185 myButtonClose = new QPushButton(tr("SMESH_BUT_CLOSE"), aGroupButtons);
186 myButtonClose->setAutoDefault(true);
187 myButtonHelp = new QPushButton(tr("SMESH_BUT_HELP"), aGroupButtons);
188 myButtonHelp->setAutoDefault(true);
190 aGroupButtonsLayout->addWidget(myButtonOk);
191 aGroupButtonsLayout->addSpacing(10);
192 aGroupButtonsLayout->addWidget(myButtonApply);
193 aGroupButtonsLayout->addSpacing(10);
194 aGroupButtonsLayout->addStretch();
195 aGroupButtonsLayout->addWidget(myButtonClose);
196 aGroupButtonsLayout->addWidget(myButtonHelp);
198 // Add mode selector, arguments and buttons to the main layout
199 aMainLayout->addWidget(aConstructorsBox);
200 aMainLayout->addWidget(myGroupArguments);
201 aMainLayout->addWidget(aGroupButtons);
203 // Initialize the dialog
207 myHelpFileName = "double_nodes_page.html";
209 // Signals and slots connections
210 connect(myGroupConstructors, SIGNAL(buttonClicked(int)), SLOT(onConstructorsClicked(int)));
212 connect(mySelectButton1, SIGNAL (clicked()), this, SLOT(onEditCurrentArgument()));
213 connect(mySelectButton2, SIGNAL (clicked()), this, SLOT(onEditCurrentArgument()));
214 connect(mySelectButton3, SIGNAL (clicked()), this, SLOT(onEditCurrentArgument()));
216 connect(myButtonOk, SIGNAL(clicked()), this, SLOT(onOk()));
217 connect(myButtonClose, SIGNAL(clicked()), this, SLOT(reject()));
218 connect(myButtonApply, SIGNAL(clicked()), this, SLOT(onApply()));
219 connect(myButtonHelp, SIGNAL(clicked()), this, SLOT(onHelp()));
221 connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), SLOT(onSelectionChanged()));
223 connect(mySMESHGUI, SIGNAL (SignalDeactivateActiveDialog()), this, SLOT(onDeactivate()));
224 connect(mySMESHGUI, SIGNAL (SignalCloseAllDialogs()), this, SLOT(reject()));
230 SMESHGUI_DuplicateNodesDlg::~SMESHGUI_DuplicateNodesDlg()
237 void SMESHGUI_DuplicateNodesDlg::Init()
239 mySMESHGUI->SetActiveDialogBox((QDialog*)this);
240 myCheckBoxNewElemGroup->setChecked(true);
241 myCheckBoxNewNodeGroup->setChecked(true);
243 // Set initial parameters
245 myCurrentLineEdit = myLineEdit1;
251 // Set selection mode
252 mySelectionMgr->installFilter(new SMESH_TypeFilter(SMESH::GROUP));
253 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
254 aViewWindow->SetSelectionMode(ActorSelection);
256 // Set construction mode
257 int operationMode = myGroupConstructors->checkedId();
258 if (operationMode < 0) {
259 // The dialog has been just displayed
261 myGroupConstructors->button(0)->setChecked(true);
263 onConstructorsClicked(operationMode);
267 \brief SLOT called to change the dialog operation mode.
268 \param constructorId id of the radio button in mode selector button group
270 void SMESHGUI_DuplicateNodesDlg::onConstructorsClicked (int constructorId)
273 myLineEdit1->clear();
274 myLineEdit2->clear();
275 myLineEdit3->clear();
281 // Set the first field as current
282 myCurrentLineEdit = myLineEdit1;
283 myCurrentLineEdit->setFocus();
285 switch (constructorId) {
288 // Set text to the group of arguments and to the first two labels
289 myGroupArguments->setTitle(tr("DUPLICATION_WITHOUT_ELEMS"));
290 myTextLabel1->setText(tr("GROUP_NODES_TO_DUPLICATE"));
291 myTextLabel2->setText(tr("GROUP_NODES_TO_REPLACE"));
293 myCheckBoxNewElemGroup->hide();
294 myCheckBoxNewNodeGroup->show();
296 // Hide the third field
297 myTextLabel3->hide();
298 mySelectButton3->hide();
305 // Set text to the group of arguments and to all the labels
306 myGroupArguments->setTitle(tr("DUPLICATION_WITH_ELEMS"));
307 myTextLabel1->setText(tr("GROUP_ELEMS_TO_DUPLICATE"));
308 myTextLabel2->setText(tr("GROUP_NODES_NOT_DUPLICATE"));
309 myTextLabel3->setText(tr("GROUP_ELEMS_TO_REPLACE"));
311 myCheckBoxNewElemGroup->show();
312 myCheckBoxNewNodeGroup->show();
314 // Show the third field
315 myTextLabel3->show();
316 mySelectButton3->show();
324 onSelectionChanged();
328 \brief SLOT called to apply changes.
330 bool SMESHGUI_DuplicateNodesDlg::onApply()
332 if ( mySMESHGUI->isActiveStudyLocked() || !isValid() )
335 BusyLocker lock( myBusy );
337 bool toCreateElemGroup = myCheckBoxNewElemGroup->isChecked();
338 bool toCreateNodeGroup = myCheckBoxNewNodeGroup->isChecked();
339 int operationMode = myGroupConstructors->checkedId();
343 SUIT_OverrideCursor aWaitCursor;
346 SMESH::SMESH_Mesh_var aMesh = myGroups1[0]->GetMesh();
347 SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor();
349 if ( operationMode == 0 ) {
350 SMESH::ListOfGroups_var g1 = new SMESH::ListOfGroups();
351 g1->length( myGroups1.count() );
352 for ( int i = 0; i < myGroups1.count(); i++ )
353 g1[i] = myGroups1[i];
354 SMESH::ListOfGroups_var g2 = new SMESH::ListOfGroups();
355 g2->length( myGroups2.count() );
356 for ( int i = 0; i < myGroups2.count(); i++ )
357 g2[i] = myGroups2[i];
359 if ( toCreateNodeGroup ) {
360 SMESH::SMESH_GroupBase_var aNewGroup =
361 aMeshEditor->DoubleNodeGroupsNew( g1.in(), g2.in() );
362 result = !CORBA::is_nil( aNewGroup );
365 result = aMeshEditor->DoubleNodeGroups( g1.in(), g2.in() );
369 SMESH::ListOfGroups_var g1 = new SMESH::ListOfGroups();
370 g1->length( myGroups1.count() );
371 for ( int i = 0; i < myGroups1.count(); i++ )
372 g1[i] = myGroups1[i];
373 SMESH::ListOfGroups_var g2 = new SMESH::ListOfGroups();
374 g2->length( myGroups2.count() );
375 for ( int i = 0; i < myGroups2.count(); i++ )
376 g2[i] = myGroups2[i];
377 SMESH::ListOfGroups_var g3 = new SMESH::ListOfGroups();
378 g3->length( myGroups3.count() );
380 for ( int i = 0; i < myGroups3.count(); i++ )
381 g3[i] = myGroups3[i];
382 if ( toCreateElemGroup || toCreateNodeGroup ) {
383 SMESH::ListOfGroups_var aNewGroups =
384 aMeshEditor->DoubleNodeElemGroups2New( g1.in(), g2.in(), g3.in(),
385 toCreateElemGroup, toCreateNodeGroup );
386 result = ( aNewGroups[ !toCreateElemGroup ].in() );
389 result = aMeshEditor->DoubleNodeElemGroups( g1.in(), g2.in(), g3.in() );
393 catch (const SALOME::SALOME_Exception& S_ex) {
394 SalomeApp_Tools::QtCatchCorbaException(S_ex);
396 catch ( const std::exception& exc ) {
397 INFOS( "Follow exception was cought:\n\t" << exc.what() );
400 INFOS( "Unknown exception was cought !!!" );
404 SUIT_MessageBox::warning(this,
405 tr("SMESH_WRN_WARNING"),
406 tr("SMESH_OPERATION_FAILED"));
411 mySelectionMgr->clearSelected();
413 SMESHGUI::Modified();
414 mySMESHGUI->updateObjBrowser(true);
416 // Reinitialize the dialog
423 \brief SLOT called to apply changes and close the dialog.
425 void SMESHGUI_DuplicateNodesDlg::onOk()
432 \brief SLOT called to close the dialog.
434 void SMESHGUI_DuplicateNodesDlg::reject()
436 disconnect(mySelectionMgr, 0, this, 0);
437 disconnect(mySMESHGUI, 0, this, 0);
438 mySMESHGUI->ResetState();
439 mySelectionMgr->clearFilters();
444 \brief SLOT called when selection changed.
446 void SMESHGUI_DuplicateNodesDlg::onSelectionChanged()
448 if ( myBusy || !isEnabled() ) return;
450 int operationMode = myGroupConstructors->checkedId();
453 mySelectionMgr->selectedObjects( aList );
454 //int aNbSel = aList.Extent();
456 QList<SMESH::SMESH_GroupBase_var> aGroups;
458 SALOME_ListIteratorOfListIO anIter ( aList );
460 for ( ; anIter.More() && ok; anIter.Next()) {
461 SMESH::SMESH_GroupBase_var aGroup = SMESH::IObjectToInterface<SMESH::SMESH_GroupBase>( anIter.Value() );
462 // check group is selected
463 ok = !CORBA::is_nil( aGroup );
464 // check groups of the same mesh are selected
466 SMESH::SMESH_Mesh_var aMesh1;
467 if ( !aGroups.isEmpty() ) aMesh1 = aGroups[0]->GetMesh();
468 SMESH::SMESH_Mesh_var aMesh2 = aGroup->GetMesh();
469 ok = CORBA::is_nil( aMesh1 ) || aMesh1->_is_equivalent( aMesh2 );
471 // check group of proper type is selected
473 SMESH::ElementType aGroupType = aGroup->GetType();
474 if ( operationMode == 0 ) {
475 ok = ( myCurrentLineEdit == myLineEdit1 && aGroupType == SMESH::NODE ) ||
476 ( myCurrentLineEdit == myLineEdit2 && aGroupType != SMESH::NODE );
479 ok = ( myCurrentLineEdit == myLineEdit1 && ( aGroupType == SMESH::EDGE ||
480 aGroupType == SMESH::FACE ) ) ||
481 ( myCurrentLineEdit == myLineEdit2 && aGroupType == SMESH::NODE ) ||
482 ( myCurrentLineEdit == myLineEdit3 && aGroupType != SMESH::NODE );
485 if ( ok ) aGroups << aGroup;
488 // Clear current field
489 myCurrentLineEdit->clear();
491 if ( ok && !aGroups.isEmpty() ) {
492 if ( myCurrentLineEdit == myLineEdit1 ) myGroups1 = aGroups;
493 else if ( myCurrentLineEdit == myLineEdit2 ) myGroups2 = aGroups;
494 else if ( myCurrentLineEdit == myLineEdit3 ) myGroups3 = aGroups;
495 CORBA::String_var name = aGroups[0]->GetName();
496 myCurrentLineEdit->setText( aGroups.count() == 1 ? QString(name).trimmed() :
497 QObject::tr( "SMESH_OBJECTS_SELECTED" ).arg( aGroups.count() ) );
500 if ( myCurrentLineEdit == myLineEdit1 ) myGroups1.clear();
501 else if ( myCurrentLineEdit == myLineEdit2 ) myGroups2.clear();
502 else if ( myCurrentLineEdit == myLineEdit3 ) myGroups3.clear();
503 myCurrentLineEdit->clear();
506 // Enable/disable "Apply and Close" and "Apply" buttons
507 bool isDataValid = isValid();
508 myButtonOk->setEnabled( isDataValid );
509 myButtonApply->setEnabled( isDataValid );
513 \brief SLOT called when selection button clicked.
515 void SMESHGUI_DuplicateNodesDlg::onEditCurrentArgument()
517 QPushButton* send = (QPushButton*)sender();
519 // Set current field for edition
520 if (send == mySelectButton1) {
521 myCurrentLineEdit = myLineEdit1;
523 else if (send == mySelectButton2) {
524 myCurrentLineEdit = myLineEdit2;
526 else if (send == mySelectButton3) {
527 myCurrentLineEdit = myLineEdit3;
530 myCurrentLineEdit->setFocus();
531 onSelectionChanged();
535 \brief Check if the input data is valid.
536 \return \c true id the data is valid
538 bool SMESHGUI_DuplicateNodesDlg::isValid()
540 return myGroupConstructors->checkedId() == 1 ?
541 ( !myGroups1.isEmpty() && !myGroups3.isEmpty() ) :
542 ( !myGroups1.isEmpty() );
547 \brief SLOT called when dialog shoud be deativated.
549 void SMESHGUI_DuplicateNodesDlg::onDeactivate()
552 mySelectionMgr->clearFilters();
554 mySMESHGUI->ResetState();
555 mySMESHGUI->SetActiveDialogBox(0);
560 \brief Receive dialog enter events.
561 Activates the dialog when the mouse cursor enters.
562 Reimplemented from QWidget class.
564 void SMESHGUI_DuplicateNodesDlg::enterEvent (QEvent*)
566 if ( !isEnabled() ) {
567 mySMESHGUI->EmitSignalDeactivateDialog();
569 mySMESHGUI->SetActiveDialogBox((QDialog*)this);
571 // Set selection mode
572 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
573 aViewWindow->SetSelectionMode(ActorSelection);
574 mySelectionMgr->installFilter(new SMESH_TypeFilter (SMESH::GROUP));
579 \brief Receive key press events.
580 Reimplemented from QWidget class.
582 void SMESHGUI_DuplicateNodesDlg::keyPressEvent( QKeyEvent* e )
584 QDialog::keyPressEvent( e );
585 if ( e->isAccepted() )
588 if ( e->key() == Qt::Key_F1 ) {
595 \brief Show the dialog help page.
597 void SMESHGUI_DuplicateNodesDlg::onHelp()
599 LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication());
601 app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName);
605 platform = "winapplication";
607 platform = "application";
609 SUIT_MessageBox::warning(this, tr("WRN_WARNING"),
610 tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE").
611 arg(app->resourceMgr()->stringValue("ExternalBrowser",
613 arg(myHelpFileName));