Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/geom.git] / src / GEOMToolsGUI / GEOMToolsGUI_MaterialPropertiesDlg.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File   : GEOMToolsGUI_MaterialPropertiesDlg.cxx
21 // Author : Margarita KARPUNINA, Open CASCADE S.A.S. (margarita.karpunina@opencascade.com)
22
23 #include "GEOMToolsGUI_MaterialPropertiesDlg.h"
24
25 #include "GeometryGUI.h"
26 #include "GEOM_Constants.h"
27 #include "GEOM_VTKPropertyMaterial.hxx"
28 #include "GEOMBase.h"
29
30 #include <QtxColorButton.h>
31 #include <QtxDoubleSpinBox.h>
32 #include <SUIT_Desktop.h>
33 #include <SUIT_MessageBox.h>
34 #include <SUIT_OverrideCursor.h>
35 #include <SUIT_ResourceMgr.h>
36 #include <SUIT_Session.h>
37 #include <SUIT_ViewManager.h>
38 #include <SALOME_ListIteratorOfListIO.hxx>
39 #include <OCCViewer_ViewModel.h>
40 #include <SVTK_ViewModel.h>
41 #include <SVTK_ViewWindow.h>
42 #include <SVTK_View.h>
43 #include <LightApp_SelectionMgr.h>
44 #include <SalomeApp_Application.h>
45 #include <SalomeApp_Study.h>
46 #include <SalomeApp_Tools.h>
47
48 #include <QCheckBox>
49 #include <QGridLayout>
50 #include <QHBoxLayout>
51 #include <QKeyEvent>
52 #include <QLabel>
53 #include <QMap>
54 #include <QMenu>
55 #include <QPushButton>
56 #include <QVBoxLayout>
57
58 #define MARGIN  9  // layout spacing
59 #define SPACING 6  // layout margin
60
61 /*!
62   \class GEOMToolsGUI_MaterialList
63   \brief Internal class, used to handle context menu event from materials list
64   \internal
65 */
66
67 /*!
68   \brief Contructor
69  */
70 GEOMToolsGUI_MaterialList::GEOMToolsGUI_MaterialList( QWidget* parent )
71   : QListWidget( parent )
72 {}
73
74 /*!
75   \brief Context menu event, emits context menu signal passing event as parameter
76 */
77 void GEOMToolsGUI_MaterialList::contextMenuEvent( QContextMenuEvent* e )
78 {
79   emit contextMenu( e );
80 }
81
82 /*!
83   \class GEOMToolsGUI_MaterialPropertiesDlg
84   \brief GEOM material properties dialog box class
85
86   The dialog box is used to set material properties for the presentation objects.
87 */
88
89 /*!
90   \brief Constructor
91   \param parent parent widget
92 */
93 GEOMToolsGUI_MaterialPropertiesDlg::GEOMToolsGUI_MaterialPropertiesDlg( QWidget* parent )
94   : QtxDialog( parent, true, true, OK | Close | Apply | Help )
95 {
96   // Set title
97   setWindowTitle( tr( "MATERIAL_PROPERTIES_TLT" ) );
98
99   // main layout
100   QVBoxLayout* main = new QVBoxLayout( mainFrame() );
101   main->setMargin( 0 );
102   main->setSpacing( SPACING );
103
104   // add top-level frame box to enclose all main widgets (excluding buttons)
105   QFrame* fr = new QFrame( mainFrame() );
106   fr->setFrameStyle( QFrame::Box | QFrame::Sunken );
107   main->addWidget( fr );
108
109   // materials list widget
110   myMaterials = new GEOMToolsGUI_MaterialList( fr );
111   // properties widget
112   QWidget* propWidget = new QWidget( fr );
113
114   // layout main widgets
115   QHBoxLayout* frLayout = new QHBoxLayout( fr );
116   frLayout->setMargin( MARGIN );
117   frLayout->setSpacing( SPACING );
118   frLayout->addWidget( myMaterials );
119   frLayout->addWidget( propWidget );
120
121   // layout for material properties widgets
122   QGridLayout* propLayout = new QGridLayout( propWidget );
123   propLayout->setMargin( 0 );
124   propLayout->setSpacing( SPACING );
125
126   // current color widgets
127   myColorLab = new QLabel( tr( "CURRENT_COLOR" ), propWidget );
128   myColor = new QtxColorButton( propWidget );
129
130   // "physical" material type widgets
131   myPhysical = new QCheckBox( tr( "PHYSICAL" ), propWidget );
132
133   // reflection components widgets
134   for ( int i = Material_Model::Ambient; i <= Material_Model::Emissive; i++ )
135   {
136     Reflection refl;
137
138     refl.label = new QLabel( tr( QString( "REFLECTION_%1" ).arg( i ).toLatin1().data() ), propWidget );
139
140     refl.color = new QtxColorButton( propWidget );
141     //refl.color->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
142
143     refl.coef = new QtxDoubleSpinBox( propWidget );
144     refl.coef->setPrecision( 4 );
145     refl.coef->setDecimals( 4 ); 
146     refl.coef->setRange( 0., 1. );
147     refl.coef->setSingleStep( 0.05 );
148     refl.coef->setMinimumWidth( 80 );
149
150     refl.enabled = new QCheckBox( tr( "ENABLED" ), propWidget );
151
152     myReflection << refl;
153   }
154
155   // shininess widgets
156   QLabel* shininessLab = new QLabel( tr( "SHININESS" ), propWidget );
157   myShininess = new QtxDoubleSpinBox( propWidget );
158   myShininess->setPrecision( 4 );
159   myShininess->setDecimals( 4 ); 
160   myShininess->setRange( 0., 1. );
161   myShininess->setSingleStep( 0.05 );
162
163   // separator widgets
164   QFrame* line1 = new QFrame( propWidget );
165   line1->setFrameStyle( QFrame::HLine | QFrame::Sunken );
166   QFrame* line2 = new QFrame( propWidget );
167   line2->setFrameStyle( QFrame::HLine | QFrame::Sunken );
168
169   // add / remove material buttons
170   myAddButton = new QPushButton( tr( "ADD_MATERIAL" ),    propWidget );
171   myDelButton = new QPushButton( tr( "DELETE_MATERIAL" ), propWidget );
172
173   // buttons layout
174   QHBoxLayout* btnLayout = new QHBoxLayout;
175   btnLayout->setMargin( 0 );
176   btnLayout->setSpacing( SPACING );
177   btnLayout->addWidget( myAddButton );
178   btnLayout->addWidget( myDelButton );
179
180   // layout all properties widgets together
181   propLayout->addWidget( myColorLab, 0, 0 );
182   propLayout->addWidget( myColor,    0, 1 );
183   propLayout->addWidget( line1, 1, 0, 1, 4 );
184   propLayout->addWidget( myPhysical,     2, 0, 1, 2 );
185   for ( int i = Material_Model::Ambient; i <= Material_Model::Emissive; i++ ) {
186     propLayout->addWidget( myReflection[i].label,   i+3, 0 );
187     propLayout->addWidget( myReflection[i].color,   i+3, 1 );
188     propLayout->addWidget( myReflection[i].coef,    i+3, 2 );
189     propLayout->addWidget( myReflection[i].enabled, i+3, 3 );
190   }
191   propLayout->addWidget( shininessLab,   7, 0 );
192   propLayout->addWidget( myShininess,    7, 2 );
193   propLayout->addWidget( line2, 8, 0, 1, 4 );
194   propLayout->setRowStretch( 9, 5 );
195   propLayout->addLayout( btnLayout, 10, 0, 1, 4 );
196
197   // initialize dialog box
198   setButtonPosition( Right, Close );
199
200   // fill in the list of materials
201   QStringList globalMaterials = myResourceMgr.materials( Material_ResourceMgr::Global );
202   QStringList userMaterials   = myResourceMgr.materials( Material_ResourceMgr::User );
203
204   QListWidgetItem* item;
205
206   // - current material
207   item = new QListWidgetItem( tr( "CURRENT_MATERIAL" ) );
208   item->setForeground( QColor( Qt::red ) );
209   item->setData( TypeRole, QVariant( Current ) );
210   myMaterials->addItem( item );
211   // - global materials
212   foreach( QString material, globalMaterials ) {
213     item = new QListWidgetItem( material );
214     item->setForeground( QColor( Qt::blue ) );
215     item->setData( TypeRole, QVariant( Global ) );
216     item->setData( NameRole, QVariant( material ) );
217     myMaterials->addItem( item );
218   }
219   // - user materials
220   foreach ( QString material, userMaterials ) {
221     item = new QListWidgetItem( material );
222     item->setData( TypeRole, QVariant( User ) );
223     item->setData( NameRole, QVariant( material ) );
224     item->setFlags( item->flags() | Qt::ItemIsEditable );
225     myMaterials->addItem( item );
226   }
227   // install event filter to the materials list to process key press events
228   myMaterials->installEventFilter( this );
229
230   // connect signals
231   // note: all widgets, that change material properties, are connected to the common signal
232   // changed(), instead of connecting directly to the slot - this allows easy temporary blocking 
233   // of the change signal
234   connect( myPhysical, SIGNAL( toggled( bool ) ), this, SIGNAL( changed() ) ); 
235   for ( int i = Material_Model::Ambient; i <= Material_Model::Emissive; i++ ) {
236     connect( myReflection[i].color,   SIGNAL( changed( QColor ) ),   this, SIGNAL( changed() ) );
237     connect( myReflection[i].coef,    SIGNAL( valueChanged( double ) ), this, SIGNAL( changed() ) );
238     connect( myReflection[i].enabled, SIGNAL( toggled( bool ) ),     this, SIGNAL( changed() ) );
239   }
240   connect( myShininess, SIGNAL( valueChanged( double ) ), this, SIGNAL( changed() ) );
241   connect( myMaterials, SIGNAL( itemSelectionChanged() ),
242            this,        SLOT( onMaterialChanged() ) );
243   connect( myMaterials, SIGNAL( itemChanged( QListWidgetItem* ) ),
244            this,        SLOT( onItemChanged( QListWidgetItem* ) ) );
245   connect( myMaterials, SIGNAL( contextMenu( QContextMenuEvent* ) ),
246            this,        SLOT( onContextMenu( QContextMenuEvent* ) ) );
247   connect( myAddButton, SIGNAL( clicked() ), this, SLOT( onAddMaterial() ) );
248   connect( myDelButton, SIGNAL( clicked() ), this, SLOT( onDeleteMaterial() ) );
249   connect( this, SIGNAL( dlgApply() ), this, SLOT( onApply() ) );
250   connect( this, SIGNAL( dlgHelp() ),  this, SLOT( onHelp() ) );
251   connect( this, SIGNAL( changed() ),  this, SLOT( onChanged() ) );
252
253   // initialize current material model according to the selection
254   myColor->setColor( SUIT_Session::session()->resourceMgr()->colorValue( "Geometry", "shading_color", QColor( 255, 0, 0 ) ) );
255   myCurrentModel.fromResources( SUIT_Session::session()->resourceMgr()->stringValue( "Geometry", "material", "Plastic" ) );
256   SalomeApp_Application* app = dynamic_cast< SalomeApp_Application* >( SUIT_Session::session()->activeApplication() );
257   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( app->activeStudy() );
258   LightApp_SelectionMgr* selMgr = app->selectionMgr();
259   if ( study ) {
260     SALOME_ListIO selected;
261     selMgr->selectedObjects( selected );
262     if ( selected.Extent() > 0 ) {
263       Handle(SALOME_InteractiveObject) io = selected.First();
264       if ( !io.IsNull() ) {
265         SUIT_ViewWindow* window = app->desktop()->activeWindow();
266         if ( window ) {
267           int mgrId = window->getViewManager()->getGlobalId();
268           PropMap propMap = study->getObjectPropMap( mgrId, io->getEntry() );
269           QString matProp = propMap.value(MATERIAL_PROP).toString();        
270           if ( !matProp.isEmpty() )
271             myCurrentModel.fromProperties( matProp );
272           QColor c = propMap.value(COLOR_PROP).value<QColor>();
273           if ( c.isValid() )
274             myColor->setColor( c );
275         }
276       }
277     }
278   }
279   
280   // finally activate current material properties
281   myMaterials->setCurrentRow( 0 );
282 }
283
284 /*!
285   \brief Destructor
286 */
287 GEOMToolsGUI_MaterialPropertiesDlg::~GEOMToolsGUI_MaterialPropertiesDlg()
288 {
289 }
290
291 /*!
292   \brief Called when "OK" button is clicked
293 */
294 void GEOMToolsGUI_MaterialPropertiesDlg::accept()
295 {
296   onApply();
297   QtxDialog::accept();
298 }
299
300 /*!
301   \brief Event filter
302   \param o sender
303   \param e event
304 */
305 bool GEOMToolsGUI_MaterialPropertiesDlg::eventFilter( QObject* o, QEvent* e )
306 {
307   // process key press event from materials list
308   if ( o == myMaterials && e->type() == QEvent::KeyPress ) {
309     QKeyEvent* ke = (QKeyEvent*)e;
310     if ( ke->key() == Qt::Key_Delete ) {
311       onDeleteMaterial();
312     }
313   }
314   return QtxDialog::eventFilter( o, e );
315 }
316
317 /*!
318   \brief Initialize dialog box widgets from material model
319   \param model material model
320 */
321 void GEOMToolsGUI_MaterialPropertiesDlg::fromModel( const Material_Model& model )
322 {
323   // reflection components
324   for ( int i = Material_Model::Ambient; i <= Material_Model::Emissive; i++ )
325   {
326     myReflection[i].color->setColor( model.color( (Material_Model::ReflectionType)i ) );
327     myReflection[i].coef->setValue( model.reflection( (Material_Model::ReflectionType)i ) );
328     myReflection[i].enabled->setChecked( model.hasReflection( (Material_Model::ReflectionType)i ) );
329   }
330   
331   // shininess
332   myShininess->setValue( model.shininess() );
333
334   // type (physical or no)
335   myPhysical->setChecked( model.isPhysical() );
336 }
337  
338 /*!
339   \brief Save values from dialog box widgets to material model
340   \param model material model to be filled in
341 */
342 void GEOMToolsGUI_MaterialPropertiesDlg::toModel( Material_Model& model ) const
343 {
344   // type (physical or no)
345   model.setPhysical( myPhysical->isChecked() );
346
347   // shininess
348   model.setShininess( myShininess->value() );
349
350   // reflection components
351   for ( int i = Material_Model::Ambient; i <= Material_Model::Emissive; i++ )
352   {
353     model.setColor     ( (Material_Model::ReflectionType)i, myReflection[i].color->color() );
354     model.setReflection( (Material_Model::ReflectionType)i, myReflection[i].coef->value() );
355     model.setReflection( (Material_Model::ReflectionType)i, myReflection[i].enabled->isChecked() );
356   }
357 }
358
359 /*!
360   \brief Find unique name for the material name
361   \param name material name template
362   \param item the item to be ignored when browsing through the materials list
363   \param addSuffix if \c true, the integrer suffix is always added to the material name (otherwise
364   suffix is added only if item name is not unique)
365   \return new unique material name
366 */
367 QString GEOMToolsGUI_MaterialPropertiesDlg::findUniqueName( const QString& name, QListWidgetItem* item, bool addSuffix )
368 {
369   bool found = false;
370   int idx = 0;
371   for( int i = 1; i < myMaterials->count(); i++ ) {
372     if ( item == myMaterials->item( i ) ) continue;
373     QString iname = myMaterials->item( i )->text();
374     if ( iname == name ) {
375       found = true;
376     }
377     else if ( iname.startsWith( name ) ) {
378       iname = iname.mid( name.length() ).trimmed();
379       bool ok = false;
380       int nx = iname.toInt( &ok );
381       if ( ok ) idx = qMax( idx, nx );
382     }
383   }
384   return found || addSuffix ? QString( "%1 %2" ).arg( name ).arg( idx+1 ) : name;
385 }
386
387 /*!
388   \brief Called when "Apply" button is pressed
389 */
390 void GEOMToolsGUI_MaterialPropertiesDlg::onApply()
391 {  
392   // save user materials
393   myResourceMgr.save();
394
395   // store selected material properties in the current model
396   toModel( myCurrentModel );
397
398   SalomeApp_Application* app = dynamic_cast< SalomeApp_Application* >( SUIT_Session::session()->activeApplication() );
399   LightApp_SelectionMgr* selMgr = app->selectionMgr();
400   SalomeApp_Study* study = dynamic_cast<SalomeApp_Study*>( app->activeStudy() );
401   
402   if ( !study ) return;
403
404   // get selection
405   SALOME_ListIO selected;
406   selMgr->selectedObjects( selected );
407   if ( selected.IsEmpty() ) return;
408
409   SUIT_ViewWindow* window = app->desktop()->activeWindow();
410   int mgrId = window->getViewManager()->getGlobalId();
411
412   // convert current material properties to the string representation
413   QString prop = myCurrentModel.toProperties();
414  
415   if ( window && window->getViewManager()->getType() == SVTK_Viewer::Type() ) {
416     // for VTK viewer
417     SVTK_ViewWindow* vtkVW = dynamic_cast<SVTK_ViewWindow*>( window );
418     if ( !vtkVW )
419       return;
420
421     SVTK_View* aView = vtkVW->getView();
422
423     // get VTK material properties from the current model
424     GEOM_VTKPropertyMaterial* vtkProp = myCurrentModel.getMaterialVTKProperty();
425
426     SUIT_OverrideCursor wc();
427
428     for ( SALOME_ListIteratorOfListIO It( selected ); It.More(); It.Next() ) {
429       // set material property to the presentation
430       aView->SetMaterial( It.Value(), vtkProp );
431       // store chosen material in the property map
432       study->setObjectProperty( mgrId, It.Value()->getEntry(), MATERIAL_PROP, prop );
433       // set correct color for the non-physical material
434       if ( !myCurrentModel.isPhysical() ) {
435         aView->SetColor( It.Value(), myColor->color() );
436         study->setObjectProperty( mgrId, It.Value()->getEntry(), COLOR_PROP, myColor->color() );
437       }
438     }
439     aView->Repaint();
440     GeometryGUI::Modified();
441   }
442   else if ( window && window->getViewManager()->getType() == OCCViewer_Viewer::Type() ) {    
443     // for OCC viewer
444     OCCViewer_Viewer* vm = dynamic_cast<OCCViewer_Viewer*>( window->getViewManager()->getViewModel() );
445     if ( !vm )
446       return;
447
448     Handle(AIS_InteractiveContext) ic = vm->getAISContext();
449
450     // get OCC material aspect from the current model
451     Graphic3d_MaterialAspect occAspect = myCurrentModel.getMaterialOCCAspect();
452
453     SUIT_OverrideCursor wc();
454
455     for ( SALOME_ListIteratorOfListIO It( selected ); It.More(); It.Next() ) {
456       Handle(GEOM_AISShape) aisShape = GEOMBase::ConvertIOinGEOMAISShape( It.Value(), true );
457       if ( !aisShape.IsNull() ) {
458         // set material property to the presentation
459         aisShape->SetMaterial( occAspect );
460         // store chosen material in the property map
461         study->setObjectProperty( mgrId, It.Value()->getEntry(), MATERIAL_PROP, prop );
462         // set correct color for the non-physical material
463         if ( !myCurrentModel.isPhysical() ) {
464           aisShape->SetShadingColor( SalomeApp_Tools::color( myColor->color() ) );
465           study->setObjectProperty( mgrId, It.Value()->getEntry(), COLOR_PROP, myColor->color() );
466           ic->RecomputePrsOnly( aisShape, Standard_False );
467         }
468         //if ( aisShape->DisplayMode() != AIS_Shaded/*aisShape->DisplayMode() == GEOM_AISShape::ShadingWithEdges*/)
469         ic->Redisplay( aisShape, Standard_False );
470       }
471     }
472     ic->UpdateCurrentViewer();
473     GeometryGUI::Modified();
474   }
475 }
476
477 /*!
478   \brief Called when "Help" button is pressed
479 */
480 void GEOMToolsGUI_MaterialPropertiesDlg::onHelp()
481 {
482   LightApp_Application* app = (LightApp_Application*)(SUIT_Session::session()->activeApplication());
483   app->onHelpContextModule( "GEOM", "material_page.html" );
484 }
485
486 /*!
487   \brief Called when user selects any material item in the materials list
488 */
489 void GEOMToolsGUI_MaterialPropertiesDlg::onMaterialChanged()
490 {
491   // get currently selected item
492   QListWidgetItem* item = myMaterials->currentItem();
493   if ( !item ) return;
494
495   bool blocked = blockSignals( true );
496
497   int type = item->data( TypeRole ).toInt();
498   if ( type == Current ) {
499     // initialize widgets from current material model
500     fromModel( myCurrentModel );
501   }
502   else {
503     // initialize widgets from chosen material model (using resources manager)
504     Material_Model model;
505     model.fromResources( item->data( NameRole ).toString(), &myResourceMgr );
506     fromModel( model );
507   }
508
509   blockSignals( blocked );
510
511   // update buttons state
512   updateState();
513 }
514
515 /*!
516   \brief Called when any material parameter is changed by the user
517 */
518 void GEOMToolsGUI_MaterialPropertiesDlg::onChanged()
519 {
520   // get currently selected item
521   QListWidgetItem* item = myMaterials->currentItem();
522   int type = item->data( TypeRole ).toInt();
523   if ( !item ) return;
524
525   if ( type == Current ) {    
526     // for the current model do not perform any actions except store changed values
527     toModel( myCurrentModel );
528   }
529   else if ( type == User ) {    
530     // for the user model, simply store the changes in the resource manager
531     Material_Model model;
532     toModel( model );
533     // check if the user model is renamed
534     QString oldName = item->data( NameRole ).toString(), newName = item->text();
535     if ( oldName == newName ) {
536       // model is not renamed: store data using current name
537       model.toResources( oldName, &myResourceMgr );
538     }
539     else {
540       // model is renamed: remove model with old name and store model using new name
541       myResourceMgr.remove( oldName );
542       model.toResources( newName, &myResourceMgr );
543       item->setData( NameRole, newName );
544     }
545   }
546   else {
547     // it is no allowed to change global material
548     // user is asked about creating of a new user material model based on the currently selected one
549     if ( SUIT_MessageBox::question( this,
550                                     tr( "GEOM_WRN_WARNING" ),
551                                     tr( "QUE_CREATE_NEW_MATERIAL" ),
552                                     QMessageBox::Yes | QMessageBox::No,
553                                     QMessageBox::Yes ) == QMessageBox::Yes ) {
554       // user has chosen creation of new user model
555       onAddMaterial();
556     }
557     else {
558       // user has rejected creation of new user model: revert changes
559       bool blocked = blockSignals( true );
560       Material_Model model;
561       model.fromResources( item->data( NameRole ).toString(), &myResourceMgr );
562       fromModel( model );
563       blockSignals( blocked );
564     }
565   }
566
567   // update buttons state
568   updateState();
569 }
570
571 /*!
572   \brief Called when user material is renamed by the user
573 */
574 void GEOMToolsGUI_MaterialPropertiesDlg::onItemChanged( QListWidgetItem* item )
575 {
576   // check new name to be unique (add suffix if necessary)
577   QString newName = item->text();
578   QString uniqueName = findUniqueName( newName, item );
579   if ( uniqueName != newName ) {
580     bool blocked = myMaterials->blockSignals( true );
581     item->setText( uniqueName );
582     myMaterials->blockSignals( blocked );
583   }
584   onChanged();
585 }                               
586
587 /*!
588   \brief Process context menu event from materials list
589 */
590 void GEOMToolsGUI_MaterialPropertiesDlg::onContextMenu( QContextMenuEvent* e )
591 {
592   QListWidgetItem* item = myMaterials->itemAt( e->pos() );
593   QMap<QAction*, int> actionMap;
594   QMenu m;
595   // rename
596   if ( item && item->data( TypeRole ).toInt() == User ) {
597     actionMap[ m.addAction( tr( "RENAME_MATERIAL" ) ) ] = 0;
598     m.addSeparator();
599   }
600   // add user material
601   actionMap[ m.addAction( tr( "ADD_MATERIAL" ) ) ] = 1;
602   // delete user material
603   if ( item && item->data( TypeRole ).toInt() == User ) {
604     actionMap[ m.addAction( tr( "DELETE_MATERIAL" ) ) ] = 2;
605   }
606   QAction* a = m.exec( e->globalPos() );
607   switch( actionMap[ a ] ) {
608   case 0:
609     // rename
610     myMaterials->editItem( item );
611     break;
612   case 1:
613     // add user material
614     onAddMaterial();
615     break;
616   case 2:
617     // delete user material
618     onDeleteMaterial();
619     break;
620   default:
621     break;
622   }
623 }
624
625 /*!
626   \brief Delete currently selected user model
627 */
628 void GEOMToolsGUI_MaterialPropertiesDlg::onDeleteMaterial()
629 {
630   QListWidgetItem* item = myMaterials->currentItem();
631   if ( item && item->data( TypeRole ).toInt() == User ) {
632     if ( SUIT_MessageBox::question( this,
633                                     tr( "GEOM_WRN_WARNING" ),
634                                     tr( "QUE_REMOVE_MATERIAL" ).arg( item->text() ),
635                                     QMessageBox::Yes | QMessageBox::No,
636                                     QMessageBox::Yes ) == QMessageBox::Yes ) {
637       myResourceMgr.remove( item->data( NameRole ).toString() );
638       delete item;
639     }
640   }
641 }
642
643 /*!
644   \brief Add new user material model
645 */
646 void GEOMToolsGUI_MaterialPropertiesDlg::onAddMaterial()
647 {
648   QString newName = findUniqueName( tr( "CUSTOM_MATERIAL" ), 0, true );
649   QListWidgetItem* item = new QListWidgetItem( newName );
650   item->setData( TypeRole, QVariant( User ) );
651   item->setData( NameRole, QVariant( newName ) );
652   item->setFlags( item->flags() | Qt::ItemIsEditable );
653   myMaterials->addItem( item );
654   
655   Material_Model model;
656   toModel( model );
657   model.toResources( newName, &myResourceMgr );
658   myMaterials->setCurrentItem( item );
659   myMaterials->editItem( item );
660 }
661
662 /*!
663   \brief Update buttons state
664 */
665 void GEOMToolsGUI_MaterialPropertiesDlg::updateState()
666 {
667   QListWidgetItem* item = myMaterials->currentItem();
668   myDelButton->setEnabled( item && item->data( TypeRole ).toInt() == User );
669   myColorLab->setEnabled( !myPhysical->isChecked() );
670   myColor->setEnabled( !myPhysical->isChecked() );
671   myReflection[0].color->setEnabled( myPhysical->isChecked() );
672 }