1 // Copyright (C) 2007-2013 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_MeshUtils.h"
33 #include "SMESHGUI_VTKUtils.h"
35 #include <SMESH_TypeFilter.hxx>
37 // SALOME GUI includes
38 #include <SUIT_Session.h>
39 #include <SUIT_ResourceMgr.h>
40 #include <SUIT_Desktop.h>
41 #include <SUIT_MessageBox.h>
42 #include <SUIT_OverrideCursor.h>
44 #include <LightApp_Application.h>
45 #include <LightApp_SelectionMgr.h>
47 #include <SalomeApp_Tools.h>
49 #include <SVTK_ViewWindow.h>
50 #include <SALOME_ListIO.hxx>
51 #include <SALOME_ListIteratorOfListIO.hxx>
54 #include <QApplication>
55 #include <QButtonGroup>
59 #include <QPushButton>
60 #include <QRadioButton>
62 #include <QHBoxLayout>
63 #include <QVBoxLayout>
66 #include <utilities.h>
67 #include <SALOMEDSClient_SObject.hxx>
70 #include <SALOMEconfig.h>
71 #include CORBA_SERVER_HEADER(SMESH_MeshEditor)
78 \brief Simple 'busy state' flag locker.
85 //! Constructor. Sets passed boolean flag to \c true.
86 BusyLocker( bool& busy ) : myBusy( busy ) { myBusy = true; }
87 //! Destructor. Clear external boolean flag passed as parameter to the constructor to \c false.
88 ~BusyLocker() { myBusy = false; }
90 bool& myBusy; //! External 'busy state' boolean flag
95 \param theModule Mesh module instance
97 SMESHGUI_DuplicateNodesDlg::SMESHGUI_DuplicateNodesDlg( SMESHGUI* theModule )
98 : QDialog( SMESH::GetDesktop( theModule ) ),
99 mySMESHGUI( theModule ),
100 mySelectionMgr( SMESH::GetSelectionMgr( theModule ) )
104 setAttribute(Qt::WA_DeleteOnClose, true);
105 setWindowTitle(tr("SMESH_DUPLICATE_TITLE"));
106 setSizeGripEnabled(true);
108 // Icons for the dialog operation modes and selection button
109 SUIT_ResourceMgr* aResMgr = SMESH::GetResourceMgr( mySMESHGUI );
110 QPixmap iconWithoutElem (aResMgr->loadPixmap("SMESH", tr("ICON_SMESH_DUPLICATE_NODES")));
111 QPixmap iconWithElem (aResMgr->loadPixmap("SMESH", tr("ICON_SMESH_DUPLICATE_NODES_WITH_ELEM")));
112 QPixmap iconElemOnly (aResMgr->loadPixmap("SMESH", tr("ICON_SMESH_DUPLICATE_ELEM_ONLY")));
113 QPixmap iconSelect (aResMgr->loadPixmap("SMESH", tr("ICON_SELECT")));
116 QVBoxLayout* aMainLayout = new QVBoxLayout(this);
117 aMainLayout->setSpacing(SPACING);
118 aMainLayout->setMargin(MARGIN);
120 // Operation modes selector
121 QGroupBox* aConstructorsBox = new QGroupBox(tr("DUPLICATION_MODE"), this);
122 myGroupConstructors = new QButtonGroup(this);
123 QHBoxLayout* aConstructorsBoxLayout = new QHBoxLayout(aConstructorsBox);
124 aConstructorsBoxLayout->setSpacing(SPACING);
125 aConstructorsBoxLayout->setMargin(MARGIN);
127 QRadioButton* aRadioButton1 = new QRadioButton(aConstructorsBox);
128 aRadioButton1->setIcon(iconWithoutElem);
129 QRadioButton* aRadioButton2 = new QRadioButton(aConstructorsBox);
130 aRadioButton2->setIcon(iconWithElem);
131 QRadioButton* aRadioButton3 = new QRadioButton(aConstructorsBox);
132 aRadioButton3->setIcon(iconElemOnly);
134 aConstructorsBoxLayout->addWidget(aRadioButton1);
135 aConstructorsBoxLayout->addWidget(aRadioButton2);
136 aConstructorsBoxLayout->addWidget(aRadioButton3);
137 myGroupConstructors->addButton(aRadioButton1, 0);
138 myGroupConstructors->addButton(aRadioButton2, 1);
139 myGroupConstructors->addButton(aRadioButton3, 2);
142 myGroupArguments = new QGroupBox(this);
143 QGridLayout* aGroupArgumentsLayout = new QGridLayout(myGroupArguments);
144 aGroupArgumentsLayout->setSpacing(SPACING);
145 aGroupArgumentsLayout->setMargin(MARGIN);
147 myTextLabel1 = new QLabel(myGroupArguments);
148 mySelectButton1 = new QPushButton(myGroupArguments);
149 mySelectButton1->setIcon(iconSelect);
150 myLineEdit1 = new QLineEdit(myGroupArguments);
151 myLineEdit1->setReadOnly(true);
153 myTextLabel2 = new QLabel(myGroupArguments);
154 mySelectButton2 = new QPushButton(myGroupArguments);
155 mySelectButton2->setIcon(iconSelect);
156 myLineEdit2 = new QLineEdit(myGroupArguments);
157 myLineEdit2->setReadOnly(true);
159 myTextLabel3 = new QLabel(myGroupArguments);
160 mySelectButton3 = new QPushButton(myGroupArguments);
161 mySelectButton3->setIcon(iconSelect);
162 myLineEdit3 = new QLineEdit(myGroupArguments);
163 myLineEdit3->setReadOnly(true);
165 myCheckBoxNewElemGroup = new QCheckBox(tr("CONSTRUCT_NEW_GROUP_ELEMENTS"), myGroupArguments);
166 myCheckBoxNewNodeGroup = new QCheckBox(tr("CONSTRUCT_NEW_GROUP_NODES"), myGroupArguments);
168 aGroupArgumentsLayout->addWidget(myTextLabel1, 0, 0);
169 aGroupArgumentsLayout->addWidget(mySelectButton1, 0, 1);
170 aGroupArgumentsLayout->addWidget(myLineEdit1, 0, 2);
171 aGroupArgumentsLayout->addWidget(myTextLabel2, 1, 0);
172 aGroupArgumentsLayout->addWidget(mySelectButton2, 1, 1);
173 aGroupArgumentsLayout->addWidget(myLineEdit2, 1, 2);
174 aGroupArgumentsLayout->addWidget(myTextLabel3, 2, 0);
175 aGroupArgumentsLayout->addWidget(mySelectButton3, 2, 1);
176 aGroupArgumentsLayout->addWidget(myLineEdit3, 2, 2);
177 aGroupArgumentsLayout->addWidget(myCheckBoxNewElemGroup, 3, 0);
178 aGroupArgumentsLayout->addWidget(myCheckBoxNewNodeGroup, 4, 0);
179 aGroupArgumentsLayout->setRowStretch(5, 1);
182 QGroupBox* aGroupButtons = new QGroupBox(this);
183 QHBoxLayout* aGroupButtonsLayout = new QHBoxLayout(aGroupButtons);
184 aGroupButtonsLayout->setSpacing(SPACING);
185 aGroupButtonsLayout->setMargin(MARGIN);
187 myButtonOk = new QPushButton(tr("SMESH_BUT_APPLY_AND_CLOSE"), aGroupButtons);
188 myButtonOk->setAutoDefault(true);
189 myButtonOk->setDefault(true);
190 myButtonApply = new QPushButton(tr("SMESH_BUT_APPLY"), aGroupButtons);
191 myButtonApply->setAutoDefault(true);
192 myButtonClose = new QPushButton(tr("SMESH_BUT_CLOSE"), aGroupButtons);
193 myButtonClose->setAutoDefault(true);
194 myButtonHelp = new QPushButton(tr("SMESH_BUT_HELP"), aGroupButtons);
195 myButtonHelp->setAutoDefault(true);
197 aGroupButtonsLayout->addWidget(myButtonOk);
198 aGroupButtonsLayout->addSpacing(10);
199 aGroupButtonsLayout->addWidget(myButtonApply);
200 aGroupButtonsLayout->addSpacing(10);
201 aGroupButtonsLayout->addStretch();
202 aGroupButtonsLayout->addWidget(myButtonClose);
203 aGroupButtonsLayout->addWidget(myButtonHelp);
205 // Add mode selector, arguments and buttons to the main layout
206 aMainLayout->addWidget(aConstructorsBox);
207 aMainLayout->addWidget(myGroupArguments);
208 aMainLayout->addWidget(aGroupButtons);
210 myCheckBoxNewElemGroup->setChecked(true);
211 myCheckBoxNewNodeGroup->setChecked(true);
213 // Initialize the dialog
217 myHelpFileName = "double_nodes_page.html";
219 // Signals and slots connections
220 connect(myGroupConstructors, SIGNAL(buttonClicked(int)), SLOT(onConstructorsClicked(int)));
222 connect(mySelectButton1, SIGNAL (clicked()), this, SLOT(onEditCurrentArgument()));
223 connect(mySelectButton2, SIGNAL (clicked()), this, SLOT(onEditCurrentArgument()));
224 connect(mySelectButton3, SIGNAL (clicked()), this, SLOT(onEditCurrentArgument()));
226 connect(myButtonOk, SIGNAL(clicked()), this, SLOT(onOk()));
227 connect(myButtonClose, SIGNAL(clicked()), this, SLOT(reject()));
228 connect(myButtonApply, SIGNAL(clicked()), this, SLOT(onApply()));
229 connect(myButtonHelp, SIGNAL(clicked()), this, SLOT(onHelp()));
231 connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), SLOT(onSelectionChanged()));
233 connect(mySMESHGUI, SIGNAL (SignalDeactivateActiveDialog()), this, SLOT(onDeactivate()));
234 connect(mySMESHGUI, SIGNAL (SignalCloseAllDialogs()), this, SLOT(reject()));
240 SMESHGUI_DuplicateNodesDlg::~SMESHGUI_DuplicateNodesDlg()
247 void SMESHGUI_DuplicateNodesDlg::Init()
249 mySMESHGUI->SetActiveDialogBox((QDialog*)this);
251 // Set initial parameters
253 myCurrentLineEdit = myLineEdit1;
259 // Set selection mode
260 mySelectionMgr->installFilter(new SMESH_TypeFilter(SMESH::GROUP));
261 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
262 aViewWindow->SetSelectionMode(ActorSelection);
264 // Set construction mode
265 int operationMode = myGroupConstructors->checkedId();
266 if (operationMode < 0) {
267 // The dialog has been just displayed
269 myGroupConstructors->button(0)->setChecked(true);
271 onConstructorsClicked(operationMode);
275 \brief SLOT called to change the dialog operation mode.
276 \param constructorId id of the radio button in mode selector button group
278 void SMESHGUI_DuplicateNodesDlg::onConstructorsClicked (int constructorId)
281 myLineEdit1->clear();
282 myLineEdit2->clear();
283 myLineEdit3->clear();
289 // Set the first field as current
290 myCurrentLineEdit = myLineEdit1;
291 myCurrentLineEdit->setFocus();
293 switch (constructorId) {
296 // Set text to the group of arguments and to the first two labels
297 myGroupArguments->setTitle(tr("DUPLICATION_WITHOUT_ELEMS"));
298 myTextLabel1->setText(tr("GROUP_NODES_TO_DUPLICATE"));
299 myTextLabel2->setText(tr("GROUP_NODES_TO_REPLACE"));
301 myCheckBoxNewElemGroup->hide();
302 myCheckBoxNewNodeGroup->show();
304 // Hide the third field
305 myTextLabel2->show();
306 mySelectButton2->show();
308 myTextLabel3->hide();
309 mySelectButton3->hide();
316 // Set text to the group of arguments and to all the labels
317 myGroupArguments->setTitle(tr("DUPLICATION_WITH_ELEMS"));
318 myTextLabel1->setText(tr("GROUP_ELEMS_TO_DUPLICATE"));
319 myTextLabel2->setText(tr("GROUP_NODES_NOT_DUPLICATE"));
320 myTextLabel3->setText(tr("GROUP_ELEMS_TO_REPLACE"));
322 myCheckBoxNewElemGroup->show();
323 myCheckBoxNewNodeGroup->show();
325 // Show the third field
326 myTextLabel2->show();
327 mySelectButton2->show();
329 myTextLabel3->show();
330 mySelectButton3->show();
337 // Set text to the group of arguments and to all the labels
338 myGroupArguments->setTitle(tr("DUPLICATION_ONLY_ELEMS"));
339 myTextLabel1->setText(tr("GROUP_ELEMS_TO_DUPLICATE"));
341 myCheckBoxNewElemGroup->show();
342 myCheckBoxNewNodeGroup->hide();
344 // Hide the second and the third field
345 myTextLabel2->hide();
346 mySelectButton2->hide();
348 myTextLabel3->hide();
349 mySelectButton3->hide();
357 onSelectionChanged();
361 \brief SLOT called to apply changes.
363 bool SMESHGUI_DuplicateNodesDlg::onApply()
365 if ( mySMESHGUI->isActiveStudyLocked() || !isValid() )
368 BusyLocker lock( myBusy );
370 bool toCreateElemGroup = myCheckBoxNewElemGroup->isChecked();
371 bool toCreateNodeGroup = myCheckBoxNewNodeGroup->isChecked();
372 int operationMode = myGroupConstructors->checkedId();
376 SUIT_OverrideCursor aWaitCursor;
377 QStringList anEntryList;
380 SMESH::SMESH_Mesh_var aMesh = myGroups1[0]->GetMesh();
381 SMESH::SMESH_MeshEditor_var aMeshEditor = aMesh->GetMeshEditor();
383 switch ( operationMode ) {
386 SMESH::ListOfGroups_var g1 = new SMESH::ListOfGroups();
387 g1->length( myGroups1.count() );
388 for ( int i = 0; i < myGroups1.count(); i++ )
389 g1[i] = myGroups1[i];
390 SMESH::ListOfGroups_var g2 = new SMESH::ListOfGroups();
391 g2->length( myGroups2.count() );
392 for ( int i = 0; i < myGroups2.count(); i++ )
393 g2[i] = myGroups2[i];
395 if ( toCreateNodeGroup ) {
396 SMESH::SMESH_GroupBase_var aNewGroup =
397 aMeshEditor->DoubleNodeGroupsNew( g1.in(), g2.in() );
398 result = !CORBA::is_nil( aNewGroup );
401 result = aMeshEditor->DoubleNodeGroups( g1.in(), g2.in() );
407 SMESH::ListOfGroups_var g1 = new SMESH::ListOfGroups();
408 g1->length( myGroups1.count() );
409 for ( int i = 0; i < myGroups1.count(); i++ )
410 g1[i] = myGroups1[i];
411 SMESH::ListOfGroups_var g2 = new SMESH::ListOfGroups();
412 g2->length( myGroups2.count() );
413 for ( int i = 0; i < myGroups2.count(); i++ )
414 g2[i] = myGroups2[i];
415 SMESH::ListOfGroups_var g3 = new SMESH::ListOfGroups();
416 g3->length( myGroups3.count() );
418 for ( int i = 0; i < myGroups3.count(); i++ )
419 g3[i] = myGroups3[i];
420 if ( toCreateElemGroup || toCreateNodeGroup ) {
421 SMESH::ListOfGroups_var aNewGroups =
422 aMeshEditor->DoubleNodeElemGroups2New( g1.in(), g2.in(), g3.in(),
423 toCreateElemGroup, toCreateNodeGroup );
424 result = ( aNewGroups[ !toCreateElemGroup ].in() );
427 result = aMeshEditor->DoubleNodeElemGroups( g1.in(), g2.in(), g3.in() );
435 if ( toCreateElemGroup )
436 groupName = SMESH::UniqueName("DoubleElements");
437 for ( int i = 0; i < myGroups1.count(); i++ )
439 SMESH::SMESH_Group_var group =
440 aMeshEditor->DoubleElements( myGroups1[i], groupName.toLatin1().data() );
441 if ( group->_is_nil() )
443 if ( toCreateElemGroup )
448 if ( _PTR(SObject) so = SMESH::FindSObject( group ))
449 anEntryList.append( so->GetID().c_str() );
456 catch (const SALOME::SALOME_Exception& S_ex) {
457 SalomeApp_Tools::QtCatchCorbaException(S_ex);
459 catch ( const std::exception& exc ) {
460 INFOS( "Follow exception was cought:\n\t" << exc.what() );
463 INFOS( "Unknown exception was cought !!!" );
467 SUIT_MessageBox::warning(this,
468 tr("SMESH_WRN_WARNING"),
469 tr("SMESH_OPERATION_FAILED"));
474 mySelectionMgr->clearSelected();
476 SMESHGUI::Modified();
477 mySMESHGUI->updateObjBrowser(true);
479 if ( !anEntryList.isEmpty())
480 if( LightApp_Application* anApp =
481 dynamic_cast<LightApp_Application*>( SUIT_Session::session()->activeApplication() ))
482 anApp->browseObjects( anEntryList, true, false );
484 // Reinitialize the dialog
491 \brief SLOT called to apply changes and close the dialog.
493 void SMESHGUI_DuplicateNodesDlg::onOk()
500 \brief SLOT called to close the dialog.
502 void SMESHGUI_DuplicateNodesDlg::reject()
504 disconnect(mySelectionMgr, 0, this, 0);
505 disconnect(mySMESHGUI, 0, this, 0);
506 mySMESHGUI->ResetState();
507 mySelectionMgr->clearFilters();
512 \brief SLOT called when selection changed.
514 void SMESHGUI_DuplicateNodesDlg::onSelectionChanged()
516 if ( myBusy || !isEnabled() ) return;
518 int operationMode = myGroupConstructors->checkedId();
521 mySelectionMgr->selectedObjects( aList );
522 //int aNbSel = aList.Extent();
524 QList<SMESH::SMESH_GroupBase_var> aGroups;
526 SALOME_ListIteratorOfListIO anIter ( aList );
528 for ( ; anIter.More() && ok; anIter.Next()) {
529 SMESH::SMESH_GroupBase_var aGroup = SMESH::IObjectToInterface<SMESH::SMESH_GroupBase>( anIter.Value() );
530 // check group is selected
531 ok = !CORBA::is_nil( aGroup );
532 // check groups of the same mesh are selected
534 SMESH::SMESH_Mesh_var aMesh1;
535 if ( !aGroups.isEmpty() ) aMesh1 = aGroups[0]->GetMesh();
536 SMESH::SMESH_Mesh_var aMesh2 = aGroup->GetMesh();
537 ok = CORBA::is_nil( aMesh1 ) || aMesh1->_is_equivalent( aMesh2 );
539 // check group of proper type is selected
541 SMESH::ElementType aGroupType = aGroup->GetType();
542 switch ( operationMode ) {
544 ok = ( myCurrentLineEdit == myLineEdit1 && aGroupType == SMESH::NODE ) ||
545 ( myCurrentLineEdit == myLineEdit2 && aGroupType != SMESH::NODE );
548 ok = ( myCurrentLineEdit == myLineEdit1 && ( aGroupType == SMESH::EDGE ||
549 aGroupType == SMESH::FACE ) ) ||
550 ( myCurrentLineEdit == myLineEdit2 && aGroupType == SMESH::NODE ) ||
551 ( myCurrentLineEdit == myLineEdit3 && aGroupType != SMESH::NODE );
554 ok = ( aGroupType != SMESH::NODE );
558 if ( ok ) aGroups << aGroup;
561 // Clear current field
562 myCurrentLineEdit->clear();
564 if ( ok && !aGroups.isEmpty() ) {
565 if ( myCurrentLineEdit == myLineEdit1 ) myGroups1 = aGroups;
566 else if ( myCurrentLineEdit == myLineEdit2 ) myGroups2 = aGroups;
567 else if ( myCurrentLineEdit == myLineEdit3 ) myGroups3 = aGroups;
568 CORBA::String_var name = aGroups[0]->GetName();
569 myCurrentLineEdit->setText( aGroups.count() == 1 ? QString(name).trimmed() :
570 QObject::tr( "SMESH_OBJECTS_SELECTED" ).arg( aGroups.count() ) );
573 if ( myCurrentLineEdit == myLineEdit1 ) myGroups1.clear();
574 else if ( myCurrentLineEdit == myLineEdit2 ) myGroups2.clear();
575 else if ( myCurrentLineEdit == myLineEdit3 ) myGroups3.clear();
576 myCurrentLineEdit->clear();
579 // Enable/disable "Apply and Close" and "Apply" buttons
580 bool isDataValid = isValid();
581 myButtonOk->setEnabled( isDataValid );
582 myButtonApply->setEnabled( isDataValid );
586 \brief SLOT called when selection button clicked.
588 void SMESHGUI_DuplicateNodesDlg::onEditCurrentArgument()
590 QPushButton* send = (QPushButton*)sender();
592 // Set current field for edition
593 if (send == mySelectButton1) {
594 myCurrentLineEdit = myLineEdit1;
596 else if (send == mySelectButton2) {
597 myCurrentLineEdit = myLineEdit2;
599 else if (send == mySelectButton3) {
600 myCurrentLineEdit = myLineEdit3;
603 myCurrentLineEdit->setFocus();
604 onSelectionChanged();
608 \brief Check if the input data is valid.
609 \return \c true if the data is valid
611 bool SMESHGUI_DuplicateNodesDlg::isValid()
613 return myGroupConstructors->checkedId() == 1 ?
614 ( !myGroups1.isEmpty() && !myGroups3.isEmpty() ) :
615 ( !myGroups1.isEmpty() );
620 \brief SLOT called when dialog shoud be deativated.
622 void SMESHGUI_DuplicateNodesDlg::onDeactivate()
625 mySelectionMgr->clearFilters();
627 mySMESHGUI->ResetState();
628 mySMESHGUI->SetActiveDialogBox(0);
633 \brief Receive dialog enter events.
634 Activates the dialog when the mouse cursor enters.
635 Reimplemented from QWidget class.
637 void SMESHGUI_DuplicateNodesDlg::enterEvent (QEvent*)
639 if ( !isEnabled() ) {
640 mySMESHGUI->EmitSignalDeactivateDialog();
642 mySMESHGUI->SetActiveDialogBox((QDialog*)this);
644 // Set selection mode
645 if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI ))
646 aViewWindow->SetSelectionMode(ActorSelection);
647 mySelectionMgr->installFilter(new SMESH_TypeFilter (SMESH::GROUP));
652 \brief Receive key press events.
653 Reimplemented from QWidget class.
655 void SMESHGUI_DuplicateNodesDlg::keyPressEvent( QKeyEvent* e )
657 QDialog::keyPressEvent( e );
658 if ( e->isAccepted() )
661 if ( e->key() == Qt::Key_F1 ) {
668 \brief Show the dialog help page.
670 void SMESHGUI_DuplicateNodesDlg::onHelp()
672 LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication());
674 app->onHelpContextModule(mySMESHGUI ? app->moduleName(mySMESHGUI->moduleName()) : QString(""), myHelpFileName);
678 platform = "winapplication";
680 platform = "application";
682 SUIT_MessageBox::warning(this, tr("WRN_WARNING"),
683 tr("EXTERNAL_BROWSER_CANNOT_SHOW_PAGE").
684 arg(app->resourceMgr()->stringValue("ExternalBrowser",
686 arg(myHelpFileName));