Salome HOME
Update copyright info (2010->2011)
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_DuplicateNodesDlg.cxx
1 //  Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
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.
10 //
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.
15 //
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
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // SMESH SMESHGUI : GUI for SMESH component
24 // File   : SMESHGUI_DuplicateNodesDlg.cxx
25 // Author : Michael ZORIN, Open CASCADE S.A.S.
26
27 // SMESH includes
28 #include "SMESHGUI_DuplicateNodesDlg.h"
29
30 #include "SMESHGUI.h"
31 #include "SMESHGUI_Utils.h"
32 #include "SMESHGUI_VTKUtils.h"
33
34 #include <SMESH_TypeFilter.hxx>
35
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>
42
43 #include <LightApp_Application.h>
44 #include <LightApp_SelectionMgr.h>
45
46 #include <SalomeApp_Tools.h>
47
48 #include <SVTK_ViewWindow.h>
49 #include <SALOME_ListIO.hxx>
50
51 // Qt includes
52 #include <QApplication>
53 #include <QButtonGroup>
54 #include <QGroupBox>
55 #include <QLabel>
56 #include <QLineEdit>
57 #include <QPushButton>
58 #include <QRadioButton>
59 #include <QCheckBox>
60 #include <QHBoxLayout>
61 #include <QVBoxLayout>
62 #include <QKeyEvent>
63
64 #include <utilities.h>
65
66 // IDL includes
67 #include <SALOMEconfig.h>
68 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
69
70 #define SPACING 6
71 #define MARGIN  11
72
73
74 /*!
75   \brief Constructor
76   \param theModule Mesh module instance
77 */
78 SMESHGUI_DuplicateNodesDlg::SMESHGUI_DuplicateNodesDlg( SMESHGUI* theModule )
79   : QDialog( SMESH::GetDesktop( theModule ) ),
80     mySMESHGUI( theModule ),
81     mySelectionMgr( SMESH::GetSelectionMgr( theModule ) )
82 {
83   // Dialog attributes
84   setModal(false);
85   setAttribute(Qt::WA_DeleteOnClose, true);
86   setWindowTitle(tr("SMESH_DUPLICATE_TITLE"));
87   setSizeGripEnabled(true);
88
89   // Icons for the dialog operation modes and selection button
90   SUIT_ResourceMgr* aResMgr = SMESH::GetResourceMgr( mySMESHGUI );
91   QPixmap iconWithoutElem (aResMgr->loadPixmap("SMESH", tr("ICON_SMESH_DUPLICATE_NODES")));
92   QPixmap iconWithElem (aResMgr->loadPixmap("SMESH", tr("ICON_SMESH_DUPLICATE_NODES_WITH_ELEM")));
93   QPixmap iconSelect (aResMgr->loadPixmap("SMESH", tr("ICON_SELECT")));
94
95   // Main layout
96   QVBoxLayout* aMainLayout = new QVBoxLayout(this);
97   aMainLayout->setSpacing(SPACING);
98   aMainLayout->setMargin(MARGIN);
99
100   // Operation modes selector
101   QGroupBox* aConstructorsBox = new QGroupBox(tr("DUPLICATION_MODE"), this);
102   myGroupConstructors = new QButtonGroup(this);
103   QHBoxLayout* aConstructorsBoxLayout = new QHBoxLayout(aConstructorsBox);
104   aConstructorsBoxLayout->setSpacing(SPACING);
105   aConstructorsBoxLayout->setMargin(MARGIN);
106
107   QRadioButton* aRadioButton1 = new QRadioButton(aConstructorsBox);
108   aRadioButton1->setIcon(iconWithoutElem);
109   QRadioButton* aRadioButton2 = new QRadioButton(aConstructorsBox);
110   aRadioButton2->setIcon(iconWithElem);
111   
112   aConstructorsBoxLayout->addWidget(aRadioButton1);
113   aConstructorsBoxLayout->addWidget(aRadioButton2);
114   myGroupConstructors->addButton(aRadioButton1, 0);
115   myGroupConstructors->addButton(aRadioButton2, 1);
116
117   // Arguments
118   myGroupArguments = new QGroupBox(this);
119   QGridLayout* aGroupArgumentsLayout = new QGridLayout(myGroupArguments);
120   aGroupArgumentsLayout->setSpacing(SPACING);
121   aGroupArgumentsLayout->setMargin(MARGIN);
122     
123   myTextLabel1 = new QLabel(myGroupArguments);
124   mySelectButton1 = new QPushButton(myGroupArguments);
125   mySelectButton1->setIcon(iconSelect);
126   myLineEdit1 = new QLineEdit(myGroupArguments);
127   myLineEdit1->setReadOnly(true);
128
129   myTextLabel2 = new QLabel(myGroupArguments);
130   mySelectButton2 = new QPushButton(myGroupArguments);
131   mySelectButton2->setIcon(iconSelect);
132   myLineEdit2 = new QLineEdit(myGroupArguments);
133   myLineEdit2->setReadOnly(true);
134
135   myTextLabel3 = new QLabel(myGroupArguments);
136   mySelectButton3 = new QPushButton(myGroupArguments);
137   mySelectButton3->setIcon(iconSelect);
138   myLineEdit3 = new QLineEdit(myGroupArguments);
139   myLineEdit3->setReadOnly(true);
140
141   myCheckBoxNewGroup = new QCheckBox(tr("CONSTRUCT_NEW_GROUP_NODES"), myGroupArguments);
142
143   aGroupArgumentsLayout->addWidget(myTextLabel1,    0, 0);
144   aGroupArgumentsLayout->addWidget(mySelectButton1, 0, 1);
145   aGroupArgumentsLayout->addWidget(myLineEdit1,     0, 2);
146   aGroupArgumentsLayout->addWidget(myTextLabel2,    1, 0);
147   aGroupArgumentsLayout->addWidget(mySelectButton2, 1, 1);
148   aGroupArgumentsLayout->addWidget(myLineEdit2,     1, 2);
149   aGroupArgumentsLayout->addWidget(myTextLabel3,    2, 0);
150   aGroupArgumentsLayout->addWidget(mySelectButton3, 2, 1);
151   aGroupArgumentsLayout->addWidget(myLineEdit3,     2, 2);
152   aGroupArgumentsLayout->addWidget(myCheckBoxNewGroup, 3, 0);
153   aGroupArgumentsLayout->setRowStretch(4, 1);
154   
155   // Buttons
156   QGroupBox* aGroupButtons = new QGroupBox(this);
157   QHBoxLayout* aGroupButtonsLayout = new QHBoxLayout(aGroupButtons);
158   aGroupButtonsLayout->setSpacing(SPACING);
159   aGroupButtonsLayout->setMargin(MARGIN);
160
161   myButtonOk = new QPushButton(tr("SMESH_BUT_APPLY_AND_CLOSE"), aGroupButtons);
162   myButtonOk->setAutoDefault(true);
163   myButtonOk->setDefault(true);
164   myButtonApply = new QPushButton(tr("SMESH_BUT_APPLY"), aGroupButtons);
165   myButtonApply->setAutoDefault(true);
166   myButtonClose = new QPushButton(tr("SMESH_BUT_CLOSE"), aGroupButtons);
167   myButtonClose->setAutoDefault(true);
168   myButtonHelp = new QPushButton(tr("SMESH_BUT_HELP"), aGroupButtons);
169   myButtonHelp->setAutoDefault(true);
170
171   aGroupButtonsLayout->addWidget(myButtonOk);
172   aGroupButtonsLayout->addSpacing(10);
173   aGroupButtonsLayout->addWidget(myButtonApply);
174   aGroupButtonsLayout->addSpacing(10);
175   aGroupButtonsLayout->addStretch();
176   aGroupButtonsLayout->addWidget(myButtonClose);
177   aGroupButtonsLayout->addWidget(myButtonHelp);
178
179   // Add mode selector, arguments and buttons to the main layout
180   aMainLayout->addWidget(aConstructorsBox);
181   aMainLayout->addWidget(myGroupArguments);
182   aMainLayout->addWidget(aGroupButtons);
183   
184   // Initialize the dialog
185   Init();
186
187   // Help file name
188   myHelpFileName = "double_nodes_page.html";
189
190   // Signals and slots connections
191   connect(myGroupConstructors, SIGNAL(buttonClicked(int)), SLOT(onConstructorsClicked(int)));
192      
193   connect(mySelectButton1, SIGNAL (clicked()), this, SLOT(onEditCurrentArgument()));
194   connect(mySelectButton2, SIGNAL (clicked()), this, SLOT(onEditCurrentArgument()));
195   connect(mySelectButton3, SIGNAL (clicked()), this, SLOT(onEditCurrentArgument()));
196
197   connect(myButtonOk,     SIGNAL(clicked()), this, SLOT(onOk()));
198   connect(myButtonClose,  SIGNAL(clicked()), this, SLOT(onClose()));
199   connect(myButtonApply,  SIGNAL(clicked()), this, SLOT(onApply()));
200   connect(myButtonHelp,   SIGNAL(clicked()), this, SLOT(onHelp()));
201   
202   connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), SLOT(onSelectionChanged()));
203
204   connect(mySMESHGUI, SIGNAL (SignalDeactivateActiveDialog()), this, SLOT(onDeactivate()));
205   connect(mySMESHGUI, SIGNAL (SignalCloseAllDialogs()), this, SLOT(onClose()));
206 }
207
208 /*!
209   \brief Destructor
210 */
211 SMESHGUI_DuplicateNodesDlg::~SMESHGUI_DuplicateNodesDlg()
212 {
213 }
214
215 /*!
216   \brief Destructor
217 */
218 void SMESHGUI_DuplicateNodesDlg::Init()
219 {
220   mySMESHGUI->SetActiveDialogBox((QDialog*)this);
221
222   // Set initial parameters
223   myBusy = false;
224   myCurrentLineEdit = myLineEdit1;
225
226   myGroup1 =  SMESH::SMESH_GroupBase::_nil();
227   myGroup2 =  SMESH::SMESH_GroupBase::_nil();
228   myGroup3 =  SMESH::SMESH_GroupBase::_nil();
229   
230   // Set selection mode
231   mySelectionMgr->installFilter(new SMESH_TypeFilter(GROUP));
232   if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
233     aViewWindow->SetSelectionMode(ActorSelection);
234   
235   // Set construction mode
236   int operationMode = myGroupConstructors->checkedId();
237   if (operationMode < 0) {
238     // The dialog has been just displayed
239     operationMode = 0;
240     myGroupConstructors->button(0)->setChecked(true);
241   }
242   onConstructorsClicked(operationMode);
243 }
244
245 /*!
246   \brief SLOT called to change the dialog operation mode.
247   \param constructorId id of the radio button in mode selector button group
248 */
249 void SMESHGUI_DuplicateNodesDlg::onConstructorsClicked (int constructorId)
250 {
251   // Clear all fields
252   myLineEdit1->clear();
253   myLineEdit2->clear();
254   myLineEdit3->clear();
255
256   // Checkbox should be checked by default
257   myCheckBoxNewGroup->setChecked(true);
258
259   // Set the first field as current
260   myCurrentLineEdit = myLineEdit1;
261   myCurrentLineEdit->setFocus();
262
263   switch (constructorId) {
264   case 0:
265     {
266       // Set text to the group of arguments and to the first two labels
267       myGroupArguments->setTitle(tr("DUPLICATION_WITHOUT_ELEMS"));
268       myTextLabel1->setText(tr("GROUP_NODES_TO_DUPLICATE"));
269       myTextLabel2->setText(tr("GROUP_NODES_TO_REPLACE"));
270
271       // Set checkbox title
272       myCheckBoxNewGroup->setText(tr("CONSTRUCT_NEW_GROUP_NODES"));
273       
274       // Hide the third field
275       myTextLabel3->hide();
276       mySelectButton3->hide();
277       myLineEdit3->hide();
278       
279       break;
280     }
281   case 1:
282     {
283       // Set text to the group of arguments and to all the labels
284       myGroupArguments->setTitle(tr("DUPLICATION_WITH_ELEMS"));
285       myTextLabel1->setText(tr("GROUP_ELEMS_TO_DUPLICATE"));
286       myTextLabel2->setText(tr("GROUP_NODES_NOT_DUPLICATE"));
287       myTextLabel3->setText(tr("GROUP_ELEMS_TO_REPLACE"));
288       
289       // Set checkbox title
290       myCheckBoxNewGroup->setText(tr("CONSTRUCT_NEW_GROUP_ELEMENTS"));
291
292       // Show the third field
293       myTextLabel3->show();
294       mySelectButton3->show();
295       myLineEdit3->show();
296
297       break;
298     }
299   }
300   
301   // Process selection
302   onSelectionChanged();
303 }
304
305 /*!
306   \brief SLOT called to apply changes.
307 */
308 bool SMESHGUI_DuplicateNodesDlg::onApply()
309 {
310   if (mySMESHGUI->isActiveStudyLocked() || !isValid())
311     return false;
312
313   myBusy = true;
314  
315   bool toCreateGroup = myCheckBoxNewGroup->isChecked();
316   int operationMode = myGroupConstructors->checkedId();
317   
318   // Apply changes
319   bool result = false;
320   SUIT_OverrideCursor aWaitCursor;
321
322   try {
323     SMESH::SMESH_Mesh_ptr aMesh =  myGroup1->GetMesh();
324     SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor();
325
326     if (operationMode == 0) {
327       if (toCreateGroup) {
328         SMESH::SMESH_GroupBase_ptr aNewGroup = 
329           aMeshEditor->DoubleNodeGroupNew(myGroup1, myGroup2);
330         if (!CORBA::is_nil(aNewGroup))
331       result = true;
332       }
333       else
334         result = aMeshEditor->DoubleNodeGroup(myGroup1, myGroup2);
335     }
336     else {
337       if (toCreateGroup) {
338         SMESH::SMESH_GroupBase_ptr aNewGroup = 
339           aMeshEditor->DoubleNodeElemGroupNew(myGroup1, myGroup2, myGroup3);
340         if (!CORBA::is_nil(aNewGroup))
341           result = true;
342       }
343       else
344         result = aMeshEditor->DoubleNodeElemGroup(myGroup1, myGroup2, myGroup3);
345     }
346   }
347   catch (const SALOME::SALOME_Exception& S_ex) {
348     SalomeApp_Tools::QtCatchCorbaException(S_ex);
349   }
350   catch ( const std::exception& exc ) {
351     INFOS( "Follow exception was cought:\n\t" << exc.what() );
352   } 
353   catch (...){
354     INFOS( "Unknown exception was cought !!!" );
355   }
356
357   if (!result) {
358     SUIT_MessageBox::warning(this,
359                              tr("SMESH_WRN_WARNING"),
360                              tr("SMESH_OPERATION_FAILED"));
361     myBusy = false;
362     return false;
363   }
364
365   // Update GUI
366   mySelectionMgr->clearSelected();
367   SMESH::UpdateView();
368   SMESHGUI::Modified();
369   mySMESHGUI->updateObjBrowser(true);
370
371   // Reinitialize the dialog
372   Init();
373   
374   return true;
375 }
376
377 /*!
378   \brief SLOT called to apply changes and close the dialog.
379 */
380 void SMESHGUI_DuplicateNodesDlg::onOk()
381 {
382   if (onApply())
383     onClose();
384 }
385
386 /*!
387   \brief SLOT called to close the dialog.
388 */
389 void SMESHGUI_DuplicateNodesDlg::onClose()
390 {
391   disconnect(mySelectionMgr, 0, this, 0);
392   disconnect(mySMESHGUI, 0, this, 0);
393   mySMESHGUI->ResetState();
394   mySelectionMgr->clearFilters();
395   reject();
396 }
397
398 /*!
399   \brief  SLOT called when selection changed.
400 */
401 void SMESHGUI_DuplicateNodesDlg::onSelectionChanged()
402 {
403   if (myBusy || !isEnabled()) return;
404   
405   // Try to get selected group
406   SALOME_ListIO aList;
407   mySelectionMgr->selectedObjects( aList );
408   int aNbSel = aList.Extent();
409
410   SMESH::SMESH_GroupBase_var aGroup = SMESH::SMESH_GroupBase::_nil();
411   if (aNbSel == 1) {
412     Handle(SALOME_InteractiveObject) IO = aList.First();
413     aGroup = SMESH::IObjectToInterface<SMESH::SMESH_GroupBase>(IO);
414
415     // Check group type
416     if (!CORBA::is_nil(aGroup)) {
417       int operationMode = myGroupConstructors->checkedId();
418       SMESH::ElementType aGroupType = aGroup->GetType();
419       bool isTypeValid = true;
420       
421       if (operationMode == 0) {
422         if ( (myCurrentLineEdit == myLineEdit1 && aGroupType != SMESH::NODE) ||
423              (myCurrentLineEdit == myLineEdit2 && aGroupType == SMESH::NODE) )
424           isTypeValid = false;
425       }
426       else if (operationMode == 1) {
427         if ( (myCurrentLineEdit == myLineEdit1 && aGroupType != SMESH::EDGE &&
428               aGroupType != SMESH::FACE) ||
429              (myCurrentLineEdit == myLineEdit2 && aGroupType != SMESH::NODE) || 
430              (myCurrentLineEdit == myLineEdit3 && aGroupType == SMESH::NODE) )
431           isTypeValid = false;
432       }
433     
434       if (!isTypeValid)
435         aGroup = SMESH::SMESH_GroupBase::_nil();
436     }
437   }
438
439   // Clear current field
440   myCurrentLineEdit->clear();
441
442   // Set corresponding SMESH group
443   if (myCurrentLineEdit == myLineEdit1) {
444     myGroup1 = SMESH::SMESH_Group::_narrow(aGroup);
445   }
446   else if (myCurrentLineEdit == myLineEdit2) {
447     myGroup2 = SMESH::SMESH_Group::_narrow(aGroup);
448   }
449   else if (myCurrentLineEdit == myLineEdit3) {
450     myGroup3 = SMESH::SMESH_Group::_narrow(aGroup);
451   }
452   
453   // Set group name
454   if (!CORBA::is_nil(aGroup))
455     myCurrentLineEdit->setText(aGroup->GetName());
456
457   // Enable/disable "Apply and Close" and "Apply" buttons
458   bool isDataValid = isValid();
459   myButtonOk->setEnabled(isDataValid);
460   myButtonApply->setEnabled(isDataValid);
461 }
462
463 /*!
464   \brief  SLOT called when selection button clicked.
465 */
466 void SMESHGUI_DuplicateNodesDlg::onEditCurrentArgument()
467 {
468   QPushButton* send = (QPushButton*)sender();
469   
470   // Set current field for edition
471   if (send == mySelectButton1) {
472     myCurrentLineEdit = myLineEdit1;
473   } 
474   else if (send == mySelectButton2) {
475     myCurrentLineEdit = myLineEdit2;
476   }
477   else if (send == mySelectButton3) {
478     myCurrentLineEdit = myLineEdit3;
479   }
480   
481   myCurrentLineEdit->setFocus();
482   onSelectionChanged();
483 }
484
485 /*!
486   \brief Check if the input data is valid.
487   \return \c true id the data is valid
488 */
489 bool SMESHGUI_DuplicateNodesDlg::isValid()
490 {
491   // Only first group (nodes/elemets to duplicate) is mandatory
492   bool isValid = !CORBA::is_nil(myGroup1);
493   
494   // First (elements to duplicate) and last groups should be defined in the second operation mode
495   if (isValid && myGroupConstructors->checkedId() == 1)
496     isValid = !CORBA::is_nil(myGroup3);
497
498   return isValid;
499 }
500
501
502 /*!
503   \brief SLOT called when dialog shoud be deativated.
504 */
505 void SMESHGUI_DuplicateNodesDlg::onDeactivate()
506 {
507   if (isEnabled()) {
508     mySelectionMgr->clearFilters();
509     setEnabled(false);
510     mySMESHGUI->ResetState();
511     mySMESHGUI->SetActiveDialogBox(0);
512   }
513 }
514
515 /*!
516   \brief Receive dialog enter events.
517   Activates the dialog when the mouse cursor enters.
518   Reimplemented from QWidget class.
519 */
520 void SMESHGUI_DuplicateNodesDlg::enterEvent (QEvent*)
521 {
522   if ( !isEnabled() ) {
523     mySMESHGUI->EmitSignalDeactivateDialog();
524     setEnabled(true);
525     mySMESHGUI->SetActiveDialogBox((QDialog*)this);
526     
527     // Set selection mode
528     if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
529       aViewWindow->SetSelectionMode(ActorSelection);
530     mySelectionMgr->installFilter(new SMESH_TypeFilter (GROUP));
531   }
532 }
533
534 /*!
535   \brief Receive close events.
536   Reimplemented from QWidget class.
537 */
538 void SMESHGUI_DuplicateNodesDlg::closeEvent (QCloseEvent*)
539 {
540   onClose();
541 }
542
543 /*!
544   \brief Receive key press events.
545   Reimplemented from QWidget class.
546 */
547 void SMESHGUI_DuplicateNodesDlg::keyPressEvent( QKeyEvent* e )
548 {
549   QDialog::keyPressEvent( e );
550   if ( e->isAccepted() )
551     return;
552
553   if ( e->key() == Qt::Key_F1 ) {
554     e->accept();
555     onHelp();
556   }
557 }
558
559 /*!
560   \brief Show the dialog help page.
561 */
562 void SMESHGUI_DuplicateNodesDlg::onHelp()
563 {
564   LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication());
565   if (app) 
566     app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName);
567   else {
568     QString platform;
569 #ifdef WIN32
570     platform = "winapplication";
571 #else
572     platform = "application";
573 #endif
574     SUIT_MessageBox::warning(this, tr("WRN_WARNING"),
575                              tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE").
576                              arg(app->resourceMgr()->stringValue("ExternalBrowser", 
577                                                                  platform)).
578                              arg(myHelpFileName));
579   }
580 }