Salome HOME
PR: merge from tag mergeto_trunk_17Jan05
[modules/kernel.git] / src / SALOMEGUI / QAD_DirListDlg.cxx
1 //  SALOME SALOMEGUI : implementation of desktop and GUI kernel
2 //
3 //  Copyright (C) 2003  CEA/DEN, EDF R&D
4 //
5 //
6 //
7 //  File   : QAD_DirListDlg.cxx
8 //  Author : Vadim SANDLER
9 //  Module : SALOME
10 //  $Header$
11
12 #include "QAD_DirListDlg.h"
13 #include "QAD_Desktop.h"
14 #include "QAD_FileDlg.h"
15 #include "QAD_MessageBox.h"
16 #include "QAD_Tools.h"
17 #include <qlayout.h>
18 #include <qlabel.h>
19 #include <qpushbutton.h>
20 #include <qapplication.h>
21 using namespace std;
22
23 #define MIN_WIDTH     400
24 #define MIN_HEIGHT    200
25 #define MARGIN_SIZE    11
26 #define SPACING_SIZE    6
27 #define SPACER_SIZE     5
28
29 /*!
30   Constructor
31 */
32 QAD_DirListDlg::QAD_DirListDlg(QWidget* parent, const char* name) 
33      : QDialog (parent, name, true, WStyle_NormalBorder | WStyle_Customize | WStyle_Title |  WStyle_SysMenu ) 
34 {
35   myEdited       = false;
36   myLastSelected = 0;
37   myEdit         = 0; 
38   myBtn          = 0;
39
40   setCaption(tr("QUICK_DIR_LIST_TLT"));
41   setSizeGripEnabled( true );
42
43   QGridLayout* topLayout = new QGridLayout(this);
44   topLayout->setMargin(MARGIN_SIZE);
45   topLayout->setSpacing(SPACING_SIZE);
46
47   myDirList = new QListBox(this);
48   myDirList->setMinimumSize(MIN_WIDTH, MIN_HEIGHT);
49 //  myDirList->setMaximumSize(MIN_WIDTH, MIN_HEIGHT);
50   myDirList->setSelectionMode(QListBox::Single);
51   myDirList->setHScrollBarMode(QListBox::AlwaysOff);
52   myDirList->horizontalScrollBar()->installEventFilter(this);
53   myDirList->verticalScrollBar()->installEventFilter(this);
54   myDirList->insertItem(tr("EMPTY_DIR"));
55   myDirList->installEventFilter(this);
56
57   QHBoxLayout* ctrlLayout = new QHBoxLayout;
58   ctrlLayout->setMargin(0);
59   ctrlLayout->setSpacing(0);
60
61   QLabel* lab = new QLabel(myDirList, tr("DIRECTORIES_LBL"), this);
62
63   QToolButton* insertBtn = new QToolButton(this);
64   insertBtn->setIconSet(QAD_Desktop::getResourceManager()->loadPixmap("QAD", tr("ICON_DIRLIST_INSERT")));
65   insertBtn->setAutoRaise(true);
66
67   QToolButton* deleteBtn = new QToolButton(this);
68   deleteBtn->setIconSet(QAD_Desktop::getResourceManager()->loadPixmap("QAD", tr("ICON_DIRLIST_DELETE")));
69   deleteBtn->setAutoRaise(true);
70
71   QToolButton* upBtn = new QToolButton(this);
72   upBtn->setIconSet(QAD_Desktop::getResourceManager()->loadPixmap("QAD", tr("ICON_DIRLIST_MOVEUP")));
73   upBtn->setAutoRaise(true);
74
75   QToolButton* downBtn = new QToolButton(this);
76   downBtn->setIconSet(QAD_Desktop::getResourceManager()->loadPixmap("QAD", tr("ICON_DIRLIST_MOVEDOWN")));
77   downBtn->setAutoRaise(true);
78   
79   ctrlLayout->addWidget(lab);
80   ctrlLayout->addItem(new QSpacerItem(SPACER_SIZE, SPACER_SIZE, QSizePolicy::Expanding, QSizePolicy::Minimum));
81   ctrlLayout->addWidget(insertBtn);
82   ctrlLayout->addWidget(deleteBtn);
83   ctrlLayout->addWidget(upBtn);
84   ctrlLayout->addWidget(downBtn);
85
86   QHBoxLayout* btnLayout = new QHBoxLayout;
87   btnLayout->setMargin(0);
88   btnLayout->setSpacing(6);
89
90   QPushButton * okBtn     = new QPushButton(tr("BUT_OK"), this);
91   QPushButton * cancelBtn = new QPushButton(tr("BUT_CANCEL"), this);
92   okBtn->setDefault(true);
93   okBtn->setAutoDefault(true);
94   cancelBtn->setAutoDefault(true);
95
96   btnLayout->addWidget(okBtn);
97   btnLayout->addItem(new QSpacerItem(SPACER_SIZE, SPACER_SIZE, QSizePolicy::Expanding, QSizePolicy::Minimum));
98   btnLayout->addWidget(cancelBtn);
99
100   topLayout->addLayout(ctrlLayout, 0, 0);
101   topLayout->addWidget(myDirList,  1, 0);
102   topLayout->addLayout(btnLayout,  2, 0);
103
104   connect(myDirList, SIGNAL(mouseButtonClicked(int, QListBoxItem*, const QPoint&)), 
105           this, SLOT(onMouseButtonClicked(int, QListBoxItem*, const QPoint&)));
106   connect(myDirList, SIGNAL(doubleClicked(QListBoxItem*)), 
107           this, SLOT(onDblClicked(QListBoxItem*)));
108   
109   connect(insertBtn, SIGNAL(clicked()), this, SLOT(onInsert()));
110   connect(deleteBtn, SIGNAL(clicked()), this, SLOT(onDelete()));
111   connect(upBtn,     SIGNAL(clicked()), this, SLOT(onUp()));
112   connect(downBtn,   SIGNAL(clicked()), this, SLOT(onDown()));
113   connect(okBtn,     SIGNAL(clicked()), this, SLOT(onOk()));
114   connect(cancelBtn, SIGNAL(clicked()), this, SLOT(reject()));
115
116   QAD_Tools::centerWidget(this, parent);
117 }
118
119 /*!
120   Destructor
121 */
122 QAD_DirListDlg::~QAD_DirListDlg() {
123 }
124
125 /*!
126   Gets list of paths
127 */
128 void QAD_DirListDlg::getPathList(QStringList& list) {
129   list.clear();
130   for (unsigned i = 0; i < myDirList->count()-1; i++)
131     list.append(myDirList->text(i));
132 }
133
134 /*!
135   Sets list of paths
136 */
137 void QAD_DirListDlg::setPathList(const QStringList& list) {
138   for (unsigned i = 0; i < list.count(); i++)
139     myDirList->insertItem(list[i], myDirList->count()-1);
140 }
141
142 /*!
143   Validates entered path, returns true if OK
144 */
145 #ifndef WNT
146 #include <pwd.h>
147 #endif
148 bool QAD_DirListDlg::validate() {
149   if (myEdited) {
150     QString dirPath = myEdit->text().stripWhiteSpace();
151 #ifndef WNT
152     if ( dirPath.startsWith( "~") ) {
153       dirPath = dirPath.remove(0,1);
154       QString user;
155       int slashPos = dirPath.find("/");
156       if ( slashPos >= 0 ) {
157         user = dirPath.left(slashPos);
158         dirPath = dirPath.mid(slashPos);
159       }
160       else {
161         user = dirPath;
162         dirPath = "";
163       }
164       if ( user.isEmpty() )
165         user = getenv( "USER" );
166
167       struct passwd* user_data = getpwnam( user.latin1() );
168       if ( user_data == NULL ) {
169         // unknown user or something another error
170         QAD_MessageBox::error1(this, 
171                                tr("ERR_ERROR"),
172                                tr("Unknown user %1").arg(user), 
173                                tr("BUT_OK"));
174         myEdit->setFocus();
175         return false;
176       }
177       dirPath = user_data->pw_dir + dirPath;
178     }
179 #endif
180     QDir dir(dirPath);
181     QListBoxItem* found = 0;
182     for (unsigned i = 0; i < myDirList->count()-1; i++) {
183       QDir aDir(myDirList->text(i));
184       if ( aDir.canonicalPath().isNull() && myDirList->text(i) == dir.absPath() ||
185           !aDir.canonicalPath().isNull() && aDir.exists() && aDir.canonicalPath() == dir.canonicalPath()) {
186           found = myDirList->item(i);
187         break;
188       }
189     }
190     if (dirPath.isEmpty()) {
191       if (found) {
192         // it should be last (empty) item in the list - nothing to do
193         return true;
194       }
195       else {
196         // delete directory from the list
197         removeDir(myLastSelected);
198         return true;
199       }
200     }
201     else {
202       if (found) {
203         if (found != myLastSelected) {
204           // it is forbidden to add directory more then once
205           QAD_MessageBox::error1(this, 
206                                  tr("ERR_ERROR"),
207                                  tr("ERR_DIRECTORY_SPECIFIED"), 
208                                  tr("BUT_OK"));
209           myEdit->setFocus();
210           return false;
211         }
212       }
213       else {
214         if (!dir.exists()) {
215           if ( QAD_MessageBox::info2(this, 
216                                      tr("WRN_WARNING"),
217                                      tr("WRN_DIRECTORY_N0T_EXIST").arg(dir.absPath()),
218                                      tr ("BUT_YES"), tr ("BUT_NO"), 
219                                      QAD_YES, QAD_NO, QAD_NO ) == QAD_NO ) {
220             myEdit->setFocus();
221             return false;
222           }
223         }
224         // append
225         appendDir(myLastSelected, dir.absPath());
226       }
227     }
228   }
229   return true;
230 }
231
232 /*!
233   Appends/changes directory
234 */
235 void QAD_DirListDlg::appendDir(QListBoxItem* item, const QString& dir) {
236   int index = myDirList->index(item);
237   if (index >= 0 && index < (int)myDirList->count()) {
238     if (index == (int)myDirList->count()-1) {
239       // it is the last item (new), well, insert it before the last (empty)
240       myDirList->insertItem(dir, myDirList->count()-1);
241     }
242     else {
243       // change item
244       myDirList->changeItem(dir, index);
245     }
246   }
247 }
248
249 /*!
250   Removes directory from list
251 */
252 void QAD_DirListDlg::removeDir(QListBoxItem* item) {
253   // do not remove last item (empty)
254   int index = myDirList->index(item);
255   if (index >= 0 && index < (int)myDirList->count()-1) {
256     delete item;
257     myLastSelected = myDirList->item(index);
258     myDirList->setSelected(myLastSelected, true);
259   }
260 }
261
262 /*!
263   KeyPress event handler, processes <Enter> and <Escape> keys
264 */
265 void QAD_DirListDlg::keyPressEvent(QKeyEvent* event) {
266   if ( myEdited ) {
267     if ( event->key() == Key_Escape ) {
268       delete myEdit;
269       delete myBtn;
270       myEdit = 0;
271       myBtn  = 0;
272       myEdited = false;
273       myDirList->setFocus();
274     }
275     return;
276   }
277   if (event->key() == Key_Return || event->key() == Key_Enter) {
278     accept();
279   }
280   QDialog::keyPressEvent(event);
281 }
282
283 /*!
284   Resize event
285 */
286 void QAD_DirListDlg::resizeEvent(QResizeEvent* event) {
287   QDialog::resizeEvent(event);
288   if ( myEdited ) {
289     myEdit->resize(myDirList->viewport()->width()-myBtn->sizeHint().width(), myEdit->height());
290     myBtn->move(myEdit->width(), myEdit->y());
291   }
292 }
293
294 /*!
295   Called when user clicks inside directories list box
296 */
297 void QAD_DirListDlg::onMouseButtonClicked(int           button, 
298                                           QListBoxItem* item, 
299                                           const QPoint& point) {
300   if (myEdited) {
301     if (!validate()) {
302       myDirList->setCurrentItem(myLastSelected);
303       myDirList->setSelected(myLastSelected, true);
304       return;
305     }
306     delete myEdit;
307     delete myBtn;
308     myEdit = 0;
309     myBtn  = 0;
310     myEdited = false;
311     myDirList->setFocus();
312   }
313   if (item) {
314     myDirList->setCurrentItem(item);
315     myDirList->setSelected(item, true);
316     myDirList->ensureCurrentVisible();
317     qApp->processEvents();
318     if (button == LeftButton && myLastSelected == item) {
319       QRect ir = myDirList->itemRect(myLastSelected);
320       
321       myEdit = new QLineEdit(myDirList->viewport());
322       myBtn  = new QToolButton(myDirList->viewport());
323       myBtn->setText(" ... ");
324       connect(myBtn, SIGNAL(clicked()), this, SLOT(onBtnClicked()));
325       myEdit->setGeometry(0, 
326                           ir.top()-(myEdit->sizeHint().height()-ir.height())/2, 
327                           myDirList->viewport()->width()-myBtn->sizeHint().width(), 
328                           myEdit->sizeHint().height());
329       myBtn->setGeometry (myEdit->width(), 
330                           ir.top()-(myEdit->sizeHint().height()-ir.height())/2, 
331                           myBtn->sizeHint().width(),
332                           myEdit->sizeHint().height());
333       connect(myEdit, SIGNAL(returnPressed()), this, SLOT(onEditFinished()));
334       myEdited = true;
335       myEdit->show();
336       myBtn->show();
337       if (myDirList->index(myLastSelected) != (int)myDirList->count()-1)
338         myEdit->setText(myLastSelected->text());
339       myEdit->selectAll();
340       myEdit->setCursorPosition(myEdit->text().length());
341       myEdit->installEventFilter(this);
342       myEdit->setFocus();
343     }
344   }
345   else {
346     myDirList->clearSelection();
347   }
348   myLastSelected = item;
349 }
350
351 /*!
352   Called when user double-clicks on any item
353 */
354 void QAD_DirListDlg::onDblClicked(QListBoxItem* item) {
355   onMouseButtonClicked(LeftButton, item, QPoint(0,0));
356 }
357
358 /*!
359   <...> (Browse dir) button slot
360 */
361 void QAD_DirListDlg::onBtnClicked() {
362   QString dir = myEdit->text().stripWhiteSpace().isEmpty() ? 
363                 QString::null : 
364                 myEdit->text().stripWhiteSpace();
365   dir = QAD_FileDlg::getExistingDirectory(this, dir, tr("SELECT_DIRECTORY"), true);
366   if (!dir.isEmpty()) {
367     myEdit->setText(dir);
368     myEdit->selectAll();
369     myEdit->setCursorPosition(myEdit->text().length());
370   }
371 }
372
373 /*!
374   Called when user finises editing of path by pressing <Enter>
375 */
376 void QAD_DirListDlg::onEditFinished() {
377   if (myEdit) {
378     if (!validate()) {
379       myDirList->setCurrentItem(myLastSelected);
380       myDirList->setSelected(myLastSelected, true);
381       return;
382     }
383     delete myEdit;
384     delete myBtn;
385     myEdit = 0;
386     myBtn  = 0;
387     myEdited = false;
388     myDirList->setFocus();
389   }
390 }
391
392 /*!
393   Event filter
394 */
395 bool QAD_DirListDlg::eventFilter(QObject* object, QEvent* event) {
396   if ( myEdited ) {
397     if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) {
398       if (object == myDirList->horizontalScrollBar() || object == myDirList->verticalScrollBar()) {
399         if (!validate()) {
400           myDirList->setCurrentItem(myLastSelected);
401           myDirList->setSelected(myLastSelected, true);
402           return true;
403         }
404         delete myEdit;
405         delete myBtn;
406         myEdit = 0;
407         myBtn  = 0;
408         myEdited = false;
409         myDirList->setFocus();
410       }
411     }
412     else if (event->type() == QEvent::KeyPress) {
413       QKeyEvent* ke = (QKeyEvent*)event;
414       if (ke->key() == Key_Tab)
415         return true;
416       if (object == myDirList) {
417         return true;
418       }
419       else if (object == myEdit) {
420         if ( ke->key() == Key_Up || ke->key() == Key_Down || ke->key() == Key_PageUp || ke->key() == Key_PageDown ||
421              ( ke->key() == Key_Home  || ke->key() == Key_End  || ke->key() == Key_Prior || ke->key() == Key_Next ) && 
422                  (ke->state() & ControlButton) ) {
423           return true;
424         }
425         else if ( ke->key() == Key_Escape ) {
426           delete myEdit;
427           delete myBtn;
428           myEdit = 0;
429           myBtn  = 0;
430           myEdited = false;
431           myDirList->setFocus();
432           return true;
433         }
434       }
435     }
436   }
437   else {
438     if (event->type() == QEvent::KeyPress) {
439       if (object == myDirList) {
440         QKeyEvent* ke = (QKeyEvent*)event;
441         if (ke->key() == Key_Return || ke->key() == Key_Enter) {
442           accept();
443         }
444         else {
445           QChar c(ke->ascii());
446           if (c.isPrint()) {
447             QListBoxItem* item = myDirList->item(myDirList->currentItem());
448             if (item) {
449               myDirList->setCurrentItem(item);
450               myDirList->setSelected(item, true);
451               myDirList->ensureCurrentVisible();
452               myLastSelected = item;
453               qApp->processEvents();
454               QRect ir = myDirList->itemRect(myLastSelected);
455                 
456               myEdit = new QLineEdit(myDirList->viewport());
457               myBtn  = new QToolButton(myDirList->viewport());
458               myBtn->setText(" ... ");
459               connect(myBtn, SIGNAL(clicked()), this, SLOT(onBtnClicked()));
460               myEdit->setGeometry(0, 
461                                   ir.top()-(myEdit->sizeHint().height()-ir.height())/2, 
462                                   myDirList->viewport()->width()-myBtn->sizeHint().width(), 
463                                   myEdit->sizeHint().height());
464               myBtn->setGeometry (myEdit->width(), 
465                                   ir.top()-(myEdit->sizeHint().height()-ir.height())/2, 
466                                   myBtn->sizeHint().width(),
467                                   myEdit->sizeHint().height());
468               connect(myEdit, SIGNAL(returnPressed()), this, SLOT(onEditFinished()));
469               myEdited = true;
470               myEdit->show();
471               myBtn->show();
472               myEdit->setText(c);
473               myEdit->setCursorPosition(myEdit->text().length());
474               myEdit->installEventFilter(this);
475               myEdit->setFocus();
476             }
477           }
478         }
479       }
480     }
481   }
482   return QDialog::eventFilter(object, event);
483 }
484
485 /*!
486   <Insert> button slot
487 */
488 void QAD_DirListDlg::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 QAD_DirListDlg::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 QAD_DirListDlg::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 QAD_DirListDlg::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 }
541
542 /*!
543   Purpose  : <OK> button slot
544 */
545 void QAD_DirListDlg::onOk() {
546   if (validate())
547     accept();
548 }