Salome HOME
83919f0aadfbb0ebab2ea30533f768dd35e7057d
[modules/gui.git] / src / Qtx / QtxInfoPanel.cxx
1 // Copyright (C) 2007-2023  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, or (at your option) any later version.
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 #include "QtxInfoPanel.h"
24
25 #include <QAction>
26 #include <QFont>
27 #include <QGroupBox>
28 #include <QLabel>
29 #include <QMap>
30 #include <QPalette>
31 #include <QSizePolicy>
32 #include <QToolButton>
33 #include <QVBoxLayout>
34 #include <QScrollArea>
35
36 /*!
37   \internal
38   \class QtxInfoPanel::Container
39   \brief Container to store widgets within info panel
40 */
41 class QtxInfoPanel::Container: public QWidget
42 {
43 public:
44   Container( QWidget* = 0 );
45   Container( const QString&, QWidget* = 0 );
46
47   void addAction( QAction*, const int );
48   void addLabel( const QString&, Qt::Alignment, const int );
49   void addGroup( const QString&, const int );
50
51   QWidget* find( const int ) const;
52
53   void remove( const int );
54   void clear();
55
56   void put( QWidget* );
57
58 private:
59   QMap<int, QWidget*> ids;
60   QGroupBox* group;
61 };
62
63 QtxInfoPanel::Container::Container( QWidget* parent )
64   : QWidget( parent ), group( 0 )
65 {
66   QVBoxLayout* l = new QVBoxLayout( this );
67   l->setContentsMargins( 0, 0, 0, 0 );
68 }
69
70 QtxInfoPanel::Container::Container( const QString& title, QWidget* parent )
71   : Container( parent )
72 {
73   QVBoxLayout* l = dynamic_cast<QVBoxLayout*>( layout() );
74   group = new QGroupBox( title );
75   group->setLayout( new QVBoxLayout() );
76   l->addWidget( group );
77 }
78
79 void QtxInfoPanel::Container::put( QWidget* widget )
80 {
81   QVBoxLayout* l = group ? dynamic_cast<QVBoxLayout*>( group->layout() ) : dynamic_cast<QVBoxLayout*>( layout() );
82   l->addWidget( widget );
83 }
84
85 void QtxInfoPanel::Container::addLabel( const QString& text, Qt::Alignment alignment, const int id )
86 {
87   QLabel* label = new QLabel( text );
88   QFont f = label->font();
89   f.setItalic( true );
90   label->setFont( f );
91   label->setAlignment( alignment );
92   label->setWordWrap( true );
93   put( label );
94   ids[ id ] = label;
95 }
96
97 void QtxInfoPanel::Container::addAction( QAction* action, const int id )
98 {
99   static const char* empty_xpm[] = {"16 16 1 1",
100                                     "   c None",
101                                     "                ",
102                                     "                ",
103                                     "                ",
104                                     "                ",
105                                     "                ",
106                                     "                ",
107                                     "                ",
108                                     "                ",
109                                     "                ",
110                                     "                ",
111                                     "                ",
112                                     "                ",
113                                     "                ",
114                                     "                ",
115                                     "                ",
116                                     "                "};
117   QToolButton* button = new QToolButton( this );
118   button->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
119   button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
120   button->setAutoRaise( true );
121   if ( action->icon().isNull() )
122     action->setIcon( QPixmap(empty_xpm) );
123   button->setDefaultAction( action );
124   put( button );
125   ids[ id ] = button;
126 }
127
128 void QtxInfoPanel::Container::addGroup( const QString& text, const int id )
129 {
130   Container* group = new Container( text, this );
131   put( group );
132   ids[ id ] = group;
133 }
134
135 QWidget* QtxInfoPanel::Container::find( const int id ) const
136 {
137   if ( ids.contains( id ) )
138     return ids[id];
139
140   QMap<int, QWidget*>::ConstIterator it;
141   QWidget* widget = 0;
142   for( it = ids.begin(); it != ids.end() && !widget; ++it )
143   {
144     Container* group = dynamic_cast<Container*>( it.value() );
145     if ( group )
146       widget = group->find( id );
147   }
148
149   return widget;
150 }
151
152 void QtxInfoPanel::Container::remove( const int id )
153 {
154   if ( ids.contains( id ) )
155   {
156     QVBoxLayout* l = group ? dynamic_cast<QVBoxLayout*>( group->layout() ) : dynamic_cast<QVBoxLayout*>( layout() );
157     l->removeWidget( ids[id] );
158     ids[id]->deleteLater();
159     l->invalidate();
160     ids.remove( id );
161   }
162 }
163
164 void QtxInfoPanel::Container::clear()
165 {
166   QVBoxLayout* l = group ? dynamic_cast<QVBoxLayout*>( group->layout() ) : dynamic_cast<QVBoxLayout*>( layout() );
167
168   QList<QWidget*> widgets = ids.values();
169   foreach( QWidget* widget, widgets )
170   {
171     l->removeWidget( widget );
172     widget->deleteLater();
173   }
174
175   l->invalidate();
176   ids.clear();
177 }
178
179
180 /*!
181   \internal
182   \class QtxInfoPanel::Title
183   \brief Info panel's title widget
184 */
185 class QtxInfoPanel::Title: public QLabel
186 {
187 public:
188   Title( QWidget* parent = 0 );
189 };
190
191 QtxInfoPanel::Title::Title( QWidget* parent )
192   : QLabel( parent )
193 {
194   setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
195   QString bg = palette().color( QPalette::Highlight ).name();
196   QString fg = palette().color( QPalette::HighlightedText ).name();
197   setStyleSheet( QString( "QLabel { background:%1; color:%2; }" ).arg( bg ).arg( fg ) );
198   setTextFormat( Qt::PlainText );
199   QFont f = font();
200   f.setBold( true );
201   setFont( f );
202   setContentsMargins( 2, 5, 2, 5 );
203 }
204
205
206 /*!
207   \class QtxInfoPanel
208   \brief Info panel which allows presenting welcome, useful hints
209   and other information dynamically, e.g. in the dock panel of main
210   application's window.
211
212   The *Info panel* normally has a title (aimed to shortly present the
213   current application's context) and a set of buttons and text labels
214   combined into the groups (which may be nested).
215
216   Buttons normally represent some quick actions which are applicable in
217   the current context. Text labels can be used to show additional information
218   like hints, proposed actions, etc.
219
220   To set the title to the panel, use method setTitle(). Text label can be
221   added to the panel with addLabel() method, action (button) is added via
222   addAction() method.
223
224   By default, items are added to the top level, untitled group. Additionally,
225   panel allows arranging items into groups; new group can be added with the
226   addGroup() method.
227
228   Each of addAction(), addLabel(), addGroup() methods return item's unique
229   identifier. This identifier can be used, for instance, to enable/disable
230   item with setEnabled() method, hide/show with setVisible() method, remove
231   from panel with remove() method. The same action can be added to the panel
232   several times, e.g. to the different groups - the corresponding buttons will
233   have different unique ids.
234
235   To remove all contents of panel, use clear() method.
236 */
237
238 /*!
239   \brief Create panel.
240   \param parent Parent widget.
241  */
242 QtxInfoPanel::QtxInfoPanel( QWidget* parent )
243   : QWidget( parent )
244 {
245   title = new Title( this );
246   container = new Container( this );
247
248   QVBoxLayout* layout = new QVBoxLayout( this );
249   layout->setContentsMargins( 0, 0, 0, 0 );
250
251   QWidget* wg = new QWidget();
252   QVBoxLayout* wg_layout = new QVBoxLayout( wg );
253   wg_layout->setContentsMargins( 0, 0, 0, 0 );
254   wg_layout->addWidget( container );
255   wg_layout->addStretch();
256   
257   QScrollArea* scroll = new QScrollArea();
258   scroll->setWidgetResizable( true );
259   scroll->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
260   scroll->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding );
261   scroll->setSizeAdjustPolicy( QScrollArea::AdjustToContents );
262   scroll->setFrameStyle( QScrollArea::NoFrame );
263   scroll->setContentsMargins( 0, 0, 0, 0 );
264   scroll->setWidget( wg );
265   
266   layout->addWidget( title );
267   layout->addWidget( scroll );
268   setTitle( "" );
269 }
270
271 /*!
272   \brief Destructor.
273 */
274 QtxInfoPanel::~QtxInfoPanel()
275 {
276 }
277
278 /*!
279   \brief Add left-aligned text label to the given group.
280   \param text Label's text.
281   \param groupId Group's identifier. Value -1 (default) is used
282   to add label to the top-level (untitled) group.
283   \return Label's unique identifier.
284 */
285 int QtxInfoPanel::addLabel( const QString& text, const int groupId )
286 {
287   return addLabel( text, Qt::AlignLeft, groupId );
288 }
289
290 /*!
291   \brief Add text label to the given group.
292   \param text Label's text.
293   \param alignment Label's alignment.
294   \param groupId Group's identifier. Value -1 (default) is used
295   to add label to the top-level (untitled) group.
296   \return Label's unique identifier.
297 */
298 int QtxInfoPanel::addLabel( const QString& text, Qt::Alignment alignment, const int groupId )
299 {
300   int id = 0;
301   Container* c = dynamic_cast<Container*>( find( groupId ) );
302   if ( c )
303   {
304     id = generateId();
305     c->addLabel( text, alignment, id );
306   }
307   return id;
308 }
309
310 /*!
311   \brief Add action button to the given group.
312   \param action Action being added (note: parent is not changed).
313   \param groupId Group's identifier. Value -1 (default) is used
314   to add button to the top-level (untitled) group.
315   \return Button's unique identifier.
316 */
317 int QtxInfoPanel::addAction( QAction* action, const int groupId )
318 {
319   int id = 0;
320   Container* c = dynamic_cast<Container*>( find( groupId ) );
321   if ( c )
322   {
323     id = generateId();
324     c->addAction( action, id );
325   }
326   return id;
327 }
328
329 /*!
330   \brief Add (sub-)group to the given group.
331   \param text Group's title.
332   \param groupId Parent group's identifier. Value -1 (default) is used
333   to add (sub-)group to the top-level (untitled) group (i.e. panel itself).
334   \return Group's unique identifier.
335 */
336 int QtxInfoPanel::addGroup( const QString& text, const int groupId )
337 {
338   int id = 0;
339   Container* c = dynamic_cast<Container*>( find( groupId ) );
340   if ( c )
341   {
342     id = generateId();
343     c->addGroup( text, id );
344   }
345   return id;
346 }
347
348 /*!
349   \brief Set panel's title.
350   \param text %Title text (empty string removes title).
351 */
352 void QtxInfoPanel::setTitle( const QString& text )
353 {
354   title->setText( text );
355   title->setVisible( !title->text().isEmpty() );
356 }
357
358 /*!
359   \brief Remove given item from panel.
360   \note If a group is removed, all its contents (recursively) is removed
361   as well.
362   \param id Item's (label's, button's, group's) identifier.
363 */
364 void QtxInfoPanel::remove( const int id )
365 {
366   QWidget* widget = find( id );
367   if ( widget )
368   {
369     Container* group = dynamic_cast<Container*>( widget->parentWidget() );
370     if ( !group )
371       group = dynamic_cast<Container*>( widget->parentWidget()->parentWidget() );
372     if ( group )
373       group->remove( id );
374   }
375 }
376
377 /*!
378   \brief Clear contents of panel of group.
379   \param groupId Group's identifier. Value -1 (default) is used
380   to clear all contents of panel.
381 */
382 void QtxInfoPanel::clear( const int groupId )
383 {
384   Container* c = dynamic_cast<Container*>( find( groupId ) );
385   if ( c )
386     c->clear();
387 }
388
389 /*!
390   \internal
391   \brief Find widget that represents given item.
392   \param id Item's (label's, button's, group's) identifier.
393   \return Item's widget (0 if not found).
394 */
395 QWidget* QtxInfoPanel::find( const int id ) const
396 {
397   if ( id == -1 )
398     return container;
399   return container->find( id );
400 }
401
402 /*!
403   \brief Change item's visibility.
404   \param id Item's (label's, button's, group's) identifier.
405   \param visible \c true to show item, \c false to hide it.
406 */
407 void QtxInfoPanel::setVisible( const int id, bool visible )
408 {
409   QWidget* widget = find( id );
410   if ( widget )
411     widget->setVisible( visible );
412 }
413
414 /*!
415   \brief Enable / disable item.
416   \param id Item's (label's, button's, group's) identifier.
417   \param enabled \c true to enable item, \c false to disable it.
418 */
419 void QtxInfoPanel::setEnabled( const int id, bool enabled )
420 {
421   QWidget* widget = find( id );
422   if ( widget )
423     widget->setEnabled( enabled );
424 }
425
426 /*!
427   \internal
428   \brief Generate new unique identifier.
429   \return Unique identifier.
430 */
431 int QtxInfoPanel::generateId() const
432 {
433   static int id = -100;
434   return --id;
435 }