Salome HOME
Fix for bug 10438: Crash during Explode on Blocks operation (Global selection on...
[modules/gui.git] / src / Qtx / QtxDirListEditor.cxx
1 #include "QtxDirListEditor.h"
2
3 #include <qlabel.h>
4 #include <qlayout.h>
5 #include <qpushbutton.h>
6 #include <qmessagebox.h>
7 #include <qfiledialog.h>
8 #include <qapplication.h>
9
10 #define MARGIN_SIZE    11
11 #define SPACING_SIZE    6
12 #define SPACER_SIZE     5
13
14 static const char* delete_icon[] = {
15 "16 16 3 1",
16 "` c #810000",
17 "  c none",
18 "# c #ffffff",
19 "                ",
20 "                ",
21 " ``#        ``# ",
22 " ````#     ``#  ",
23 "  ````#   ``#   ",
24 "    ```# `#     ",
25 "     `````#     ",
26 "      ```#      ",
27 "     `````#     ",
28 "    ```# ``#    ",
29 "   ```#   ``#   ",
30 "  ```#     `#   ",
31 "  ```#      `#  ",
32 "   `#        `# ",
33 "                ",
34 "                "
35 };
36
37 static const char* insert_icon[] = {
38 "16 16 5 1",
39 "` c #000000",
40 ". c #ffff00",
41 "# c #9d9da1",
42 "  c none",
43 "b c #ffffff",
44 "                ",
45 "                ",
46 " #  #b #.       ",
47 "  # #.#.` ` `   ",
48 "  .#.b####   `  ",
49 " ### ..         ",
50 "  . # .#     `  ",
51 " #` #.          ",
52 "    #        `  ",
53 "  `             ",
54 "             `  ",
55 "  `             ",
56 "             `  ",
57 "  ` ` ` ` ` `   ",
58 "                ",
59 "                "
60 };
61
62 static const char* movedown_icon[] = {
63 "16 16 2 1",
64 "` c #000000",
65 "  c none",
66 "                ",
67 "                ",
68 "         ```    ",
69 "        ```     ",
70 "       ```      ",
71 "       ```      ",
72 "       ```      ",
73 "       ```      ",
74 "   ```````````  ",
75 "    `````````   ",
76 "     ```````    ",
77 "      `````     ",
78 "       ```      ",
79 "        `       ",
80 "                ",
81 "                "
82 };
83
84 static const char* moveup_icon[] = {
85 "16 16 2 1",
86 "` c #000000",
87 "  c none",
88 "                ",
89 "                ",
90 "        `       ",
91 "       ```      ",
92 "      `````     ",
93 "     ```````    ",
94 "    `````````   ",
95 "   ```````````  ",
96 "       ```      ",
97 "       ```      ",
98 "       ```      ",
99 "       ```      ",
100 "      ```       ",
101 "     ```        ",
102 "                ",
103 "                "
104 };
105
106 /*!
107   Constructor
108 */
109 QtxDirListEditor::QtxDirListEditor( QWidget* parent )
110 : QWidget( parent )
111 {
112   myEdited       = false;
113   myLastSelected = 0;
114   myEdit         = 0; 
115   myBtn          = 0;
116
117   QGridLayout* topLayout = new QGridLayout(this);
118   topLayout->setMargin(0);
119   topLayout->setSpacing(0);
120   
121   setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
122   
123   myDirList = new QListBox(this);
124   myDirList->setSelectionMode(QListBox::Single);
125   myDirList->setHScrollBarMode(QListBox::AlwaysOff);
126   myDirList->horizontalScrollBar()->installEventFilter(this);
127   myDirList->verticalScrollBar()->installEventFilter(this);
128   myDirList->insertItem(tr("<empty>"));
129   myDirList->installEventFilter(this);
130
131   QHBoxLayout* ctrlLayout = new QHBoxLayout;
132   ctrlLayout->setMargin(0);
133   ctrlLayout->setSpacing(0);
134
135   // QLabel* lab = new QLabel(myDirList, tr("DIRECTORIES_LBL"), this);
136
137   QToolButton* insertBtn = new QToolButton(this);
138   insertBtn->setIconSet(QPixmap( insert_icon ));
139   insertBtn->setAutoRaise(true);
140
141   QToolButton* deleteBtn = new QToolButton(this);
142   deleteBtn->setIconSet(QPixmap( delete_icon ));
143   deleteBtn->setAutoRaise(true);
144
145   QToolButton* upBtn = new QToolButton(this);
146   upBtn->setIconSet(QPixmap( moveup_icon ));
147   upBtn->setAutoRaise(true);
148
149   QToolButton* downBtn = new QToolButton(this);
150   downBtn->setIconSet(QPixmap( movedown_icon ));
151   downBtn->setAutoRaise(true);
152   
153   // ctrlLayout->addWidget(lab);
154   ctrlLayout->addItem(new QSpacerItem(SPACER_SIZE, SPACER_SIZE, QSizePolicy::Expanding, QSizePolicy::Minimum));
155   ctrlLayout->addWidget(insertBtn);
156   ctrlLayout->addWidget(deleteBtn);
157   ctrlLayout->addWidget(upBtn);
158   ctrlLayout->addWidget(downBtn);
159
160   QHBoxLayout* btnLayout = new QHBoxLayout;
161   btnLayout->setMargin(0);
162   btnLayout->setSpacing(6);
163   
164   topLayout->addLayout(ctrlLayout, 0, 0);
165   topLayout->addWidget(myDirList,  1, 0);
166   topLayout->addLayout(btnLayout,  2, 0);
167
168   connect(myDirList, SIGNAL(mouseButtonClicked(int, QListBoxItem*, const QPoint&)), 
169           this, SLOT(onMouseButtonClicked(int, QListBoxItem*, const QPoint&)));
170   connect(myDirList, SIGNAL(doubleClicked(QListBoxItem*)), 
171           this, SLOT(onDblClicked(QListBoxItem*)));
172   
173   connect(insertBtn, SIGNAL(clicked()), this, SLOT(onInsert()));
174   connect(deleteBtn, SIGNAL(clicked()), this, SLOT(onDelete()));
175   connect(upBtn,     SIGNAL(clicked()), this, SLOT(onUp()));
176   connect(downBtn,   SIGNAL(clicked()), this, SLOT(onDown()));
177 }
178
179 /*!
180   Destructor
181 */
182 QtxDirListEditor::~QtxDirListEditor()
183 {
184 }
185
186 /*!
187   Gets list of paths
188 */
189 void QtxDirListEditor::getPathList(QStringList& list)
190 {
191   list.clear();
192   for (unsigned i = 0; i < myDirList->count()-1; i++)
193     list.append(myDirList->text(i));
194 }
195
196 /*!
197   Sets list of paths
198 */
199 void QtxDirListEditor::setPathList(const QStringList& list) {
200   myDirList->clear();
201   myDirList->insertItem(tr("<empty>"));
202   for (unsigned i = 0; i < list.count(); i++)
203     myDirList->insertItem(list[i], myDirList->count()-1);
204 }
205
206 /*!
207   Validates entered path, returns true if OK
208 */
209 bool QtxDirListEditor::validate()
210 {
211   if ( myEdited )
212   {
213     QString dirPath = QFileInfo( myEdit->text().stripWhiteSpace() ).absFilePath();
214 /*
215 #ifndef WNT
216     if ( dirPath.startsWith( "~") ) {
217       dirPath = dirPath.remove(0,1);
218       QString user;
219       int slashPos = dirPath.find("/");
220       if ( slashPos >= 0 ) {
221         user = dirPath.left(slashPos);
222         dirPath = dirPath.mid(slashPos);
223       }
224       else {
225         user = dirPath;
226         dirPath = "";
227       }
228       if ( user.isEmpty() )
229         user = getenv( "USER" );
230
231       struct passwd* user_data = getpwnam( user.latin1() );
232       if ( user_data == NULL ) {
233         // unknown user or something another error
234         QMessageBox::critical(this, 
235                               tr("Error"),
236                               tr("Unknown user %1").arg(user), 
237                               tr("Ok"));
238         myEdit->setFocus();
239         return false;
240       }
241       dirPath = user_data->pw_dir + dirPath;
242     }
243 #endif
244 */
245     QDir dir(dirPath);
246     QListBoxItem* found = 0;
247     for (unsigned i = 0; i < myDirList->count()-1; i++) {
248       QDir aDir(myDirList->text(i));
249       if ( aDir.canonicalPath().isNull() && myDirList->text(i) == dir.absPath() ||
250           !aDir.canonicalPath().isNull() && aDir.exists() && aDir.canonicalPath() == dir.canonicalPath()) {
251           found = myDirList->item(i);
252         break;
253       }
254     }
255     if (dirPath.isEmpty()) {
256       if (found) {
257         // it should be last (empty) item in the list - nothing to do
258         return true;
259       }
260       else {
261         // delete directory from the list
262         removeDir(myLastSelected);
263         return true;
264       }
265     }
266     else {
267       if (found) {
268         if (found != myLastSelected) {
269           // it is forbidden to add directory more then once
270           QMessageBox::critical(this, 
271                                 tr("Error"),
272                                 tr("Directory already specified."), 
273                                 tr("Ok"));
274           myEdit->setFocus();
275           return false;
276         }
277       }
278       else {
279         if (!dir.exists()) {
280           if ( QMessageBox::information(this, 
281                                         tr("Warning"),
282                                         tr("%1\n\nThe directory doesn't exist.\nAdd directory anyway?").arg(dir.absPath()),
283                                         tr("Yes"), tr("No"), QString::null, 1, 1) == 1) {
284             myEdit->setFocus();
285             return false;
286           }
287         }
288         // append
289         appendDir(myLastSelected, dir.absPath());
290       }
291     }
292   }
293   return true;
294 }
295
296 /*!
297   Appends/changes directory
298 */
299 void QtxDirListEditor::appendDir(QListBoxItem* item, const QString& dir) {
300   int index = myDirList->index(item);
301   if (index >= 0 && index < (int)myDirList->count()) {
302     if (index == (int)myDirList->count()-1) {
303       // it is the last item (new), well, insert it before the last (empty)
304       myDirList->insertItem(dir, myDirList->count()-1);
305     }
306     else {
307       // change item
308       myDirList->changeItem(dir, index);
309     }
310   }
311 }
312
313 /*!
314   Removes directory from list
315 */
316 void QtxDirListEditor::removeDir(QListBoxItem* item) {
317   // do not remove last item (empty)
318   int index = myDirList->index(item);
319   if (index >= 0 && index < (int)myDirList->count()-1) {
320     delete item;
321     myLastSelected = myDirList->item(index);
322     myDirList->setSelected(myLastSelected, true);
323   }
324 }
325
326 /*!
327   Resize event
328 */
329 void QtxDirListEditor::resizeEvent(QResizeEvent* event) {
330   QWidget::resizeEvent(event);
331   if ( myEdited ) {
332     myEdit->resize(myDirList->viewport()->width()-myBtn->sizeHint().width(), myEdit->height());
333     myBtn->move(myEdit->width(), myEdit->y());
334   }
335 }
336
337 /*!
338   Called when user clicks inside directories list box
339 */
340 void QtxDirListEditor::onMouseButtonClicked(int           button, 
341                                             QListBoxItem* item, 
342                                             const QPoint& point) {
343   if (myEdited) {
344     if (!validate()) {
345       myDirList->setCurrentItem(myLastSelected);
346       myDirList->setSelected(myLastSelected, true);
347       return;
348     }
349     delete myEdit;
350     delete myBtn;
351     myEdit = 0;
352     myBtn  = 0;
353     myEdited = false;
354     myDirList->setFocus();
355   }
356   if (item) {
357     myDirList->setCurrentItem(item);
358     myDirList->setSelected(item, true);
359     myDirList->ensureCurrentVisible();
360     qApp->processEvents();
361     if (button == LeftButton && myLastSelected == item) {
362       QRect ir = myDirList->itemRect(myLastSelected);
363       
364       myEdit = new QLineEdit(myDirList->viewport());
365       myBtn  = new QToolButton(myDirList->viewport());
366       myBtn->setText(" ... ");
367       connect(myBtn, SIGNAL(clicked()), this, SLOT(onBtnClicked()));
368       myEdit->setGeometry(0, 
369                           ir.top()-(myEdit->sizeHint().height()-ir.height())/2, 
370                           myDirList->viewport()->width()-myBtn->sizeHint().width(), 
371                           myEdit->sizeHint().height());
372       myBtn->setGeometry (myEdit->width(), 
373                           ir.top()-(myEdit->sizeHint().height()-ir.height())/2, 
374                           myBtn->sizeHint().width(),
375                           myEdit->sizeHint().height());
376       connect(myEdit, SIGNAL(returnPressed()), this, SLOT(onEditFinished()));
377       myEdited = true;
378       myEdit->show();
379       myBtn->show();
380       if (myDirList->index(myLastSelected) != (int)myDirList->count()-1)
381         myEdit->setText(myLastSelected->text());
382       myEdit->selectAll();
383       myEdit->setCursorPosition(myEdit->text().length());
384       myEdit->installEventFilter(this);
385       myEdit->setFocus();
386     }
387   }
388   else {
389     myDirList->clearSelection();
390   }
391   myLastSelected = item;
392 }
393
394 /*!
395   Called when user double-clicks on any item
396 */
397 void QtxDirListEditor::onDblClicked(QListBoxItem* item) {
398   onMouseButtonClicked(LeftButton, item, QPoint(0,0));
399 }
400
401 /*!
402   <...> (Browse dir) button slot
403 */
404 void QtxDirListEditor::onBtnClicked() {
405   QString dir = myEdit->text().stripWhiteSpace().isEmpty() ? 
406                 QString::null : 
407                 myEdit->text().stripWhiteSpace();
408
409   dir = QFileDialog::getExistingDirectory(dir, this, 0, tr("Select directory"), true);
410
411   if (!dir.isEmpty()) {
412     myEdit->setText(dir);
413     myEdit->selectAll();
414     myEdit->setCursorPosition(myEdit->text().length());
415   }
416 }
417
418 /*!
419   Called when user finises editing of path by pressing <Enter>
420 */
421 void QtxDirListEditor::onEditFinished() {
422   if (myEdit) {
423     if (!validate()) {
424       myDirList->setCurrentItem(myLastSelected);
425       myDirList->setSelected(myLastSelected, true);
426       return;
427     }
428     myEdit->deleteLater();
429     myBtn->deleteLater();
430     myEdit = 0;
431     myBtn  = 0;
432     myEdited = false;
433     myDirList->setFocus();
434   }
435 }
436
437 /*!
438   Event filter
439 */
440 bool QtxDirListEditor::eventFilter(QObject* object, QEvent* event) {
441   if ( myEdited ) {
442     if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) {
443       if (object == myDirList->horizontalScrollBar() || object == myDirList->verticalScrollBar()) {
444         if (!validate()) {
445           myDirList->setCurrentItem(myLastSelected);
446           myDirList->setSelected(myLastSelected, true);
447           return true;
448         }
449         delete myEdit;
450         delete myBtn;
451         myEdit = 0;
452         myBtn  = 0;
453         myEdited = false;
454         myDirList->setFocus();
455       }
456     }
457     else if (event->type() == QEvent::KeyPress) {
458       QKeyEvent* ke = (QKeyEvent*)event;
459       if (ke->key() == Key_Tab)
460         return true;
461       if (object == myDirList) {
462         return true;
463       }
464       else if (object == myEdit) {
465         if ( ke->key() == Key_Up || ke->key() == Key_Down || ke->key() == Key_PageUp || ke->key() == Key_PageDown ||
466              ( ke->key() == Key_Home  || ke->key() == Key_End  || ke->key() == Key_Prior || ke->key() == Key_Next ) && 
467                  (ke->state() & ControlButton) ) {
468           return true;
469         }
470         else if ( ke->key() == Key_Escape ) {
471           delete myEdit;
472           delete myBtn;
473           myEdit = 0;
474           myBtn  = 0;
475           myEdited = false;
476           myDirList->setFocus();
477           return true;
478         }
479       }
480     }
481   }
482   return QWidget::eventFilter(object, event);
483 }
484
485 /*!
486   <Insert> button slot
487 */
488 void QtxDirListEditor::onInsert() {
489   if (!myEdited) {
490     myLastSelected = 0;
491     onMouseButtonClicked(LeftButton, myDirList->item(myDirList->count()-1), QPoint(0,0));
492     onMouseButtonClicked(LeftButton, myDirList->item(myDirList->count()-1), QPoint(0,0));
493   }
494 }
495
496 /*!
497   <Delete> button slot
498 */
499 void QtxDirListEditor::onDelete() {
500   if (!myEdited && myDirList->currentItem() >=0) {
501     removeDir(myDirList->item(myDirList->currentItem()));
502     myDirList->setFocus();
503   }
504 }
505
506 /*!
507   <Move up> button slot
508 */
509 void QtxDirListEditor::onUp() {
510   if (!myEdited && myLastSelected) {
511     int index = myDirList->currentItem();
512     if (index > 0 && index < (int)myDirList->count()-1 && myDirList->isSelected(index)) {
513       QString t = myDirList->text(index-1);
514       myDirList->changeItem(myDirList->text(index), index-1);
515       myDirList->changeItem(t, index);
516       myDirList->setCurrentItem(index-1);
517       myLastSelected = myDirList->item(index-1);
518       myDirList->setSelected(myLastSelected, true);
519       myDirList->setFocus();
520     }
521   }
522 }
523
524 /*!
525   <Move down> button slot
526 */
527 void QtxDirListEditor::onDown() {
528   if (!myEdited && myLastSelected) {
529     int index = myDirList->currentItem();
530     if (index >= 0 && index < (int)myDirList->count()-2 && myDirList->isSelected(index)) {
531       QString t = myDirList->text(index+1);
532       myDirList->changeItem(myDirList->text(index), index+1);
533       myDirList->changeItem(t, index);
534       myDirList->setCurrentItem(index+1);
535       myLastSelected = myDirList->item(index+1);
536       myDirList->setSelected(myLastSelected, true);
537       myDirList->setFocus();
538     }
539   }
540 }