1 // SUPERV SUPERVGUI : GUI for Supervisor component
3 // Copyright (C) 2003 CEA/DEN, EDF R&D
7 // File : SUPERVGUI_ManagePortsDlg.cxx
8 // Author : Alexander SLADKOV
13 #include "SUIT_Desktop.h"
14 #include "SUIT_Session.h"
16 #include "SUPERVGUI_ManagePortsDlg.h"
17 #include "SUPERVGUI_CanvasNode.h"
18 #include "SUPERVGUI_CanvasPort.h"
19 #include "SUPERVGUI_CanvasControlNode.h"
20 #include "SUPERVGUI.h"
24 #include <qpushbutton.h>
26 #include <qgroupbox.h>
28 static const char* gTypes[] =
29 {"string", "boolean", "char", "short", "int", "long", "float", "double", "objref"};
31 static const char* const add_pix_data[] = {
37 "....................",
38 "....................",
39 "....................",
40 "....................",
41 "........##a.........",
42 "........##b.........",
43 "........##b.........",
44 "........##b.........",
45 "........##b.........",
46 "...############a....",
47 "...############b....",
48 "...abbbb##bbbbbb....",
49 "........##b.........",
50 "........##b.........",
51 "........##b.........",
52 "........##b.........",
53 "........abb.........",
54 "....................",
55 "....................",
56 "...................."};
58 static const char* const del_pix_data[] = {
80 static const char* const up_pix_data[] = {
104 static const char* const down_pix_data[] = {
132 SUPERVGUI_ManagePortsDlg::SUPERVGUI_ManagePortsDlg( SUPERVGUI_CanvasNode* theNode )
133 : QDialog( SUIT_Session::session()->activeApplication()->desktop(), 0, false, WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu )
140 void SUPERVGUI_ManagePortsDlg::init()
142 setName( "SUPERVGUI_ManagePortsDlg" );
144 SUPERV_CNode aCNode = myNode->getEngine();
145 setCaption( tr( "TIT_MANAGE_PORTS" ) + aCNode->Name() );
147 QGridLayout* aBaseLayout = new QGridLayout( this );
148 aBaseLayout->setMargin( 11 );
149 aBaseLayout->setSpacing( 6 );
151 // -- name and type upper line widgets --
152 QLabel* aNameLbl = new QLabel( tr( "NAME_LBL") , this );
153 myNameEdt = new QLineEdit( this );
154 QLabel* aTypeLbl = new QLabel( tr( "TYPE_LBL" ), this );
155 myTypeCombo = new QComboBox( false, this ); // input field not editable
157 aBaseLayout->addWidget( aNameLbl, 0, 0 );
158 aBaseLayout->addWidget( myNameEdt, 0, 1 );
159 aBaseLayout->addWidget( aTypeLbl, 0, 2 );
160 aBaseLayout->addWidget( myTypeCombo, 0, 3 );
161 aBaseLayout->setColStretch( 1, 1 );
162 aBaseLayout->setColStretch( 3, 1 );
164 // -- common Input/Output variables --
165 QPixmap adPix( (const char**) add_pix_data );
166 QPixmap rmPix( (const char**) del_pix_data );
167 QPixmap upPix( (const char**) up_pix_data );
168 QPixmap dnPix( (const char**) down_pix_data );
170 // -- Input ports group box --
171 QGroupBox* anInputGr = new QGroupBox( 1, Qt::Vertical, tr( "INPUT" ), this );
172 anInputGr->layout()->setSpacing( 6 );
173 anInputGr->layout()->setMargin( 11 );
175 myInList = new QListBox( anInputGr );
176 myInList->setSelectionMode( QListBox::Single );
178 QGroupBox* anInputBtnGr = new QGroupBox( 0, Qt::Vertical, anInputGr );
179 anInputBtnGr->setFrameStyle( QFrame::NoFrame );
180 anInputBtnGr->layout()->setSpacing( 0 );
181 anInputBtnGr->layout()->setMargin( 0 );
183 QVBoxLayout* anInputBtnLay = new QVBoxLayout( anInputBtnGr->layout() );
184 anInputBtnLay->layout()->setSpacing( 6 );
185 anInputBtnLay->layout()->setMargin( 0 );
187 QPushButton* anAddInputBtn = new QPushButton( anInputBtnGr );
188 anAddInputBtn->setPixmap( adPix );
189 QPushButton* aDeleteInputBtn = new QPushButton( anInputBtnGr );
190 aDeleteInputBtn->setPixmap( rmPix );
191 QPushButton* anUpInputBtn = new QPushButton( anInputBtnGr );
192 anUpInputBtn->setPixmap( upPix );
193 QPushButton* aDownInputBtn = new QPushButton( anInputBtnGr );
194 aDownInputBtn->setPixmap( dnPix );
196 connect( anAddInputBtn, SIGNAL( clicked() ), this, SLOT( addInput() ) );
197 connect( aDeleteInputBtn, SIGNAL( clicked() ), this, SLOT( removeInput() ) );
198 connect( anUpInputBtn, SIGNAL( clicked() ), this, SLOT( upInput() ) );
199 connect( aDownInputBtn, SIGNAL( clicked() ), this, SLOT( downInput() ) );
201 anInputBtnLay->addWidget( anAddInputBtn );
202 anInputBtnLay->addWidget( aDeleteInputBtn );
203 anInputBtnLay->addItem( new QSpacerItem( 1, 16, QSizePolicy::Maximum, QSizePolicy::MinimumExpanding ) );
204 anInputBtnLay->addWidget( anUpInputBtn );
205 anInputBtnLay->addWidget( aDownInputBtn );
206 anInputBtnLay->addItem( new QSpacerItem( 1, 16, QSizePolicy::Maximum, QSizePolicy::MinimumExpanding ) );
208 aBaseLayout->addMultiCellWidget( anInputGr, 1, 1, 0, 1 );
210 // -- Output ports group box --
211 QGroupBox* anOutputGr = new QGroupBox( 1, Qt::Vertical, tr( "OUTPUT" ), this );
212 anOutputGr->layout()->setSpacing( 6 );
213 anOutputGr->layout()->setMargin( 11 );
215 myOutList = new QListBox( anOutputGr );
216 myOutList->setSelectionMode( QListBox::Single );
218 QGroupBox* anOutputBtnGr = new QGroupBox( 0, Qt::Vertical, anOutputGr );
219 anOutputBtnGr->setFrameStyle( QFrame::NoFrame );
220 anOutputBtnGr->layout()->setSpacing( 0 );
221 anOutputBtnGr->layout()->setMargin( 0 );
223 QVBoxLayout* anOutputBtnLay = new QVBoxLayout( anOutputBtnGr->layout() );
224 anOutputBtnLay->layout()->setSpacing( 6 );
225 anOutputBtnLay->layout()->setMargin( 0 );
227 QPushButton* anAddOutputBtn = new QPushButton( anOutputBtnGr );
228 anAddOutputBtn->setPixmap( adPix );
229 QPushButton* aDeleteOutputBtn = new QPushButton( anOutputBtnGr );
230 aDeleteOutputBtn->setPixmap( rmPix );
231 QPushButton* anUpOutputBtn = new QPushButton( anOutputBtnGr );
232 anUpOutputBtn->setPixmap( upPix );
233 QPushButton* aDownOutputBtn = new QPushButton( anOutputBtnGr );
234 aDownOutputBtn->setPixmap( dnPix );
236 connect( anAddOutputBtn, SIGNAL( clicked() ), this, SLOT( addOutput() ) );
237 connect( aDeleteOutputBtn, SIGNAL( clicked() ), this, SLOT( removeOutput() ) );
238 connect( anUpOutputBtn, SIGNAL( clicked() ), this, SLOT( upOutput() ) );
239 connect( aDownOutputBtn, SIGNAL( clicked() ), this, SLOT( downOutput() ) );
241 anOutputBtnLay->addWidget( anAddOutputBtn );
242 anOutputBtnLay->addWidget( aDeleteOutputBtn );
243 anOutputBtnLay->addItem( new QSpacerItem( 1, 16, QSizePolicy::Maximum, QSizePolicy::MinimumExpanding ) );
244 anOutputBtnLay->addWidget( anUpOutputBtn );
245 anOutputBtnLay->addWidget( aDownOutputBtn );
246 anOutputBtnLay->addItem( new QSpacerItem( 1, 16, QSizePolicy::Maximum, QSizePolicy::MinimumExpanding ) );
248 aBaseLayout->addMultiCellWidget( anOutputGr, 1, 1, 2, 3 );
250 // -- Ok / Cancel buttons line at the bottom of dialog --
251 QGroupBox* aBtnBox = new QGroupBox( this );
252 aBtnBox->setColumnLayout( 0, Qt::Vertical );
253 aBtnBox->layout()->setSpacing( 0 );
254 aBtnBox->layout()->setMargin( 0 );
256 QHBoxLayout* aBtnLayout = new QHBoxLayout( aBtnBox->layout() );
257 aBtnLayout->setAlignment( Qt::AlignTop );
258 aBtnLayout->setSpacing( 6 );
259 aBtnLayout->setMargin( 11 );
261 QPushButton* aOkBtn = new QPushButton( tr( "BUT_OK" ), aBtnBox );
262 QPushButton* aCancelBtn = new QPushButton( tr( "BUT_CANCEL" ), aBtnBox );
263 connect( aOkBtn, SIGNAL( clicked() ), this, SLOT( accept() ) );
264 connect( aCancelBtn, SIGNAL( clicked() ), this, SLOT( reject() ) );
266 aBtnLayout->addWidget( aOkBtn );
267 aBtnLayout->addStretch();
268 aBtnLayout->addWidget( aCancelBtn );
270 aBaseLayout->addMultiCellWidget( aBtnBox, 2, 2, 0, 3 );
273 connect( myInList,SIGNAL(currentChanged(QListBoxItem*)), this, SLOT(itemChanged(QListBoxItem*)));
274 connect( myOutList, SIGNAL(currentChanged(QListBoxItem*)), this, SLOT(itemChanged(QListBoxItem*)));
275 connect( myNameEdt, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&)));
276 connect( myTypeCombo, SIGNAL(activated(const QString&)), this, SLOT(typeChanged(const QString&)));
278 myNode->getMain()->lockedGraph( true );
280 // asv : 11.01.05 : if a node is a loop node, then only INPUT ports can be added/removed
281 if ( myNode->getNodeType() == SUPERV::LoopNode ) {
282 myOutList->setEnabled( false );
283 anAddOutputBtn->setEnabled( false );
284 aDeleteOutputBtn->setEnabled( false );
285 anUpOutputBtn->setEnabled( false );
286 aDownOutputBtn->setEnabled( false );
294 SUPERVGUI_ManagePortsDlg::~SUPERVGUI_ManagePortsDlg() {
298 * Set the ports as entered by user (order, name/type, etc.) and close the dialog
300 void SUPERVGUI_ManagePortsDlg::accept() {
301 myNode->getMain()->Editing(); // PAL6170: GUI->Engine: setting "Editing" flag
302 // 1. set the ports to Engine's CNode
303 SUPERV_INode aINode = myNode->getInlineNode();
304 if ( !SUPERV_isNull( aINode ) ) {
306 const bool isLoop = ( myNode->getNodeType() == SUPERV::LoopNode );
308 // 1.1 delete all ports (delete CanvasPorts, they delete SUPERV_Ports)
309 QObjectList* oldPorts = myNode->queryList("SUPERVGUI_CanvasPort");
310 QObjectListIt it( *oldPorts ); // iterate over the old ports
313 // asv : 11.01.05 : fix for a bug: for Loop node, removal of an Input Port
314 // automatically removes the corresponding Output Port. So for Loops the
315 // oldPorts list should be filtered to include only Input Ports.
316 // But I'll filter Gate-s as well..
317 QObjectList portsToRemove;
318 while ( (obj = it.current()) != 0 ) {
320 SUPERV::Port_var aPort = ((SUPERVGUI_CanvasPort*)obj)->getEngine();
321 if ( !aPort->IsGate() && ( !isLoop || aPort->IsInput() ) )
322 portsToRemove.append( obj );
324 delete oldPorts; // delete the list, not the objects
326 // portsToRemove list contains:
327 // for Loop node: all INPUT ports except Gates
328 // for other Inline: all INPUT and OUTPUT ports except Gates
329 it = QObjectListIt( portsToRemove );
330 while ( (obj = it.current()) != 0 ) {
332 ((SUPERVGUI_CanvasPort*)obj)->remove();
335 // 1.2 create new ports in INode and CanvasPort in myNode
338 for ( i = 0; i < myInList->count(); i++ ) {
339 item = (PortListItem*)myInList->item( i );
340 aPort = aINode->InPort( item->PortName.latin1(), item->PortType.latin1() );
341 myNode->createPort( aPort.in() );
342 // asv : 11.01.05 : for Loop nodes do the same as in SUPERVGUI_CanvasStartNode::addInputPort()
344 SUPERVGUI_CanvasStartNode* aStartLoopNode = (SUPERVGUI_CanvasStartNode*)myNode;
345 aStartLoopNode->merge();
346 aStartLoopNode->getCoupled()->merge();
349 // creating Out-ports, except LoopNode-s
350 for ( i = 0; i < myOutList->count() && !isLoop; i++ ) {
351 item = (PortListItem*)myOutList->item( i );
352 aPort = aINode->OutPort( item->PortName.latin1(), item->PortType.latin1() );
353 myNode->createPort( aPort.in() );
356 // 2. update the node's presentation
357 myNode->getMain()->getCanvas()->update();
360 // 3. close the dialog
361 myNode->getMain()->lockedGraph( false );
367 * Simply close the dialog
369 void SUPERVGUI_ManagePortsDlg::reject() {
370 myNode->getMain()->lockedGraph( false );
376 * Update current values on show event
378 void SUPERVGUI_ManagePortsDlg::showEvent( QShowEvent* theEvent ) {
380 QDialog::showEvent( theEvent );
384 * Initialize In/Out tables with values from the given node
386 void SUPERVGUI_ManagePortsDlg::init( const SUPERVGUI_CanvasNode* theNode ) {
388 MESSAGE("ERROR: SUPERVGUI_ManagePortsDlg: the CanvasNode is nil!");
392 SUPERV_INode aINode = myNode->getInlineNode();
393 if ( SUPERV_isNull( aINode ) ) {
394 MESSAGE("ERROR: SUPERVGUI_ManagePortsDlg: the node of wrong type is found (not InLine node)!");
398 // 1. fill myTypeCombo with all available types
399 myTypeCombo->insertStrList( gTypes );
401 // 2. fill Input and Output listboxes with Ports' names/types
403 SUPERV_Ports aPorts = aINode->Ports();
404 for ( int i=0; i < aPorts->length(); i++ ) {
405 if ( aPorts[i]->IsGate() )
407 if ( aPorts[i]->IsInput() )
408 new PortListItem( myInList, aPorts[i]->Name(), aPorts[i]->Type() );
410 new PortListItem( myOutList, aPorts[i]->Name(), aPorts[i]->Type() );
414 void SUPERVGUI_ManagePortsDlg::addPort( QListBox* theLB ) {
417 QString name = myNameEdt->text();
418 if ( !name.isNull() && name.length() ) {
419 bool found = false; // check if already exists -- and don't allow if yes
420 for ( int i = 0; i < theLB->count(); i++ ) {
421 if ( ((PortListItem*)theLB->item(i))->PortName == name ) {
427 QMessageBox::warning( SUIT_Session::session()->activeApplication()->desktop(), tr("ERROR"), tr("MSG_PORT_EXIST") );
429 new PortListItem( theLB, name, myTypeCombo->currentText() );
434 * called on 'X' button press - remove selected port item
436 void SUPERVGUI_ManagePortsDlg::removePort( QListBox* theLB ) {
440 const int i = theLB->currentItem();
442 delete theLB->item( i );
446 * called on up/down key press - move the selected list box item from position 'from' to position 'to'
448 void SUPERVGUI_ManagePortsDlg::moveItem( QListBox* theLB, const int from, const int to ) {
452 // disconnect itemChanged - it leads to crash if there was only 1 item left
453 disconnect( theLB, SIGNAL(currentChanged(QListBoxItem*)), this, SLOT(itemChanged(QListBoxItem*)));
455 if ( from >= 0 && from < theLB->count() && to >=0 && to < theLB->count() ) {
456 QListBoxItem* item = theLB->item( from );
457 theLB->takeItem( item );
458 theLB->insertItem( item, to );
459 theLB->setCurrentItem( item );
460 theLB->setSelected( item, true );
464 connect( theLB, SIGNAL(currentChanged(QListBoxItem*)), this, SLOT(itemChanged(QListBoxItem*)));
468 * move the selected item UP
470 void SUPERVGUI_ManagePortsDlg::moveUp( QListBox* theLB ) {
473 const int i = theLB->currentItem();
474 moveItem( theLB, i, i-1 );
478 * move the selected item DOWN
480 void SUPERVGUI_ManagePortsDlg::moveDown( QListBox* theLB ) {
483 const int i = theLB->currentItem();
484 moveItem( theLB, i, i+1 );
489 * returns true if there is a current and selected item in the given listbox and it
490 * equals to the given item.
492 bool isEditingItem( const QListBoxItem* item, const QListBox* theLB ) {
493 return item && item == theLB->item( theLB->currentItem() ) && theLB->isSelected( item );
497 * called when name is changed. Tries to change name of the item, which was
498 * the last selected by user item in myInList or myOutList (myLastItem)
500 void SUPERVGUI_ManagePortsDlg::nameChanged( const QString& name ) {
501 if ( isEditingItem( myLastItem, myInList ) || isEditingItem( myLastItem, myOutList ) ) {
502 ((PortListItem*)myLastItem)->PortName = name;
503 //myLastItem->listBox()->repaint( true );
504 // it would be much better to change the item and repaint it -- but -- repaint()
505 // is done only after a while, which is not good.. so -- "cheating" around
506 const int i = myLastItem->listBox()->index( myLastItem );
507 moveItem( myLastItem->listBox(), i, i );
512 * called when type item in myTypeCombo is changed. Tries to change type
513 * of the last selected by user item in myInList or myOutList (myLastItem)
515 void SUPERVGUI_ManagePortsDlg::typeChanged( const QString& type ) {
516 if ( isEditingItem( myLastItem, myInList ) || isEditingItem( myLastItem, myOutList ) ) {
517 ((PortListItem*)myLastItem)->PortType = type;
518 //myLastItem->listBox()->repaint( true );
519 // it would be much better to change the item and repaint it -- but -- repaint()
520 // is done only after a while, which is not good.. so -- "cheating" around
521 const int i = myLastItem->listBox()->index( myLastItem );
522 moveItem( myLastItem->listBox(), i, i );
527 * called when new item became "currentItem" in any myInList or myOutList listboxes.
529 void SUPERVGUI_ManagePortsDlg::itemChanged( QListBoxItem * item ) {
530 if ( !item ) // after remove, etc..
533 // disable nameChanged, typeChanged callbacks
534 disconnect( myNameEdt, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&)));
535 disconnect( myTypeCombo, SIGNAL(activated(const QString&)), this, SLOT(typeChanged(const QString&)));
538 myNameEdt->setText( ((PortListItem*)item)->PortName );
539 for ( int i = 0; i < myTypeCombo->count(); i++ )
540 if ( myTypeCombo->text( i ) == ((PortListItem*)item)->PortType ) {
541 myTypeCombo->setCurrentItem( i );
545 // connect back nameChanged, typeChanged
546 connect( myNameEdt, SIGNAL(textChanged(const QString&)), this, SLOT(nameChanged(const QString&)));
547 connect( myTypeCombo, SIGNAL(activated(const QString&)), this, SLOT(typeChanged(const QString&)));
554 * Port parameters dialog definition (taken from SUPERVGUI_Node.cxx without change)
556 SUPERVGUI_PortParamsDlg::SUPERVGUI_PortParamsDlg(const QStringList& thePortsNames)
557 : QDialog(SUIT_Session::session()->activeApplication()->desktop(), 0, true, WStyle_Customize | WStyle_NormalBorder | WStyle_Title | WStyle_SysMenu ),
558 myPortsNames( thePortsNames )
560 setSizeGripEnabled( true );
561 setCaption("Port parameters");
563 QGridLayout* aBaseLayout = new QGridLayout( this );
564 aBaseLayout->setMargin( 11 ); aBaseLayout->setSpacing( 6 );
566 QLabel* aNameLbl = new QLabel("Port Name", this );
567 aBaseLayout->addWidget(aNameLbl, 0, 0);
569 myNameTxt = new QLineEdit( this );
570 aNameLbl->setBuddy( myNameTxt );
571 aBaseLayout->addWidget(myNameTxt, 0, 1);
573 QLabel* aTypeLbl = new QLabel("Value Type", this );
574 aBaseLayout->addWidget(aTypeLbl, 1, 0);
576 myTypeTxt = new QComboBox( this );
577 aTypeLbl->setBuddy( myTypeTxt );
578 myTypeTxt->insertStrList( gTypes );
579 aBaseLayout->addWidget(myTypeTxt, 1, 1);
581 QGroupBox* aBtnBox = new QGroupBox( this );
582 aBtnBox->setColumnLayout( 0, Qt::Vertical );
583 aBtnBox->layout()->setSpacing( 0 ); aBtnBox->layout()->setMargin( 0 );
584 QHBoxLayout* aBtnLayout = new QHBoxLayout( aBtnBox->layout() );
585 aBtnLayout->setAlignment( Qt::AlignTop );
586 aBtnLayout->setSpacing( 6 ); aBtnLayout->setMargin( 11 );
588 aBaseLayout->addMultiCellWidget( aBtnBox, 2, 2, 0, 1 );
590 QPushButton* aOKBtn = new QPushButton( tr( "BUT_OK" ), aBtnBox );
591 connect( aOKBtn, SIGNAL( clicked() ), this, SLOT( clickOnOk() ) );
592 aBtnLayout->addWidget( aOKBtn );
594 aBtnLayout->addStretch();
596 QPushButton* aCancelBtn = new QPushButton( tr("BUT_CANCEL"), aBtnBox );
597 connect( aCancelBtn, SIGNAL( clicked() ), this, SLOT( reject() ) );
598 aBtnLayout->addWidget( aCancelBtn );
601 void SUPERVGUI_PortParamsDlg::clickOnOk()
603 if (getName().isEmpty() || getType().isEmpty())
604 QMessageBox::warning( SUIT_Session::session()->activeApplication()->desktop(), tr( "ERROR" ), tr( "MSG_CANT_CREATE_PORT" ) );
605 else if (myPortsNames.contains(getName()))
606 QMessageBox::warning( SUIT_Session::session()->activeApplication()->desktop(), tr("ERROR"), tr("MSG_PORT_EXIST") );