#ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tulip/TypeConverter.h" #include "tulip/SuperGraph.h" #include "tulip/PropertyProxyContainer.h" #include "tulip/MetricProxy.h" #include "tulip/StringProxy.h" #include "tulip/SelectionProxy.h" #include "tulip/LayoutProxy.h" #include "tulip/IntProxy.h" #include "tulip/ColorsProxy.h" #include "tulip/SizesProxy.h" #include "tulip/GlGraph.h" #include "tulip/PropertyWidgets.h" #include "tulip/ClusterTree.h" #include "PropertySlider.h" #include "PropertyDialog.h" #define TABLEBUFSIZE 100 using namespace std; //================================================================================================== PropertyDialog::PropertyDialog(GlGraph *glwidget, QWidget* parent, const char* name, bool modal, WFlags fl) : PropertyDialogData(parent, name, modal) { glWidget=glwidget; _filterSelection=false; vScrollEdgePos=0; vScrollNodePos=0; vScrollNode=tableNodes->verticalScrollBar(); vScrollEdge=tableEdges->verticalScrollBar(); tableNodes->setColumnReadOnly(0, true); tableNodes->horizontalHeader()->setLabel(0, tr("Nodes")); tableEdges->setColumnReadOnly(0, true); tableEdges->horizontalHeader()->setLabel(0, tr("Edges")); connect(localProperties, SIGNAL(selectionChanged(QListViewItem*)), SLOT(changePropertyName(QListViewItem*))); connect(inheritedProperties, SIGNAL(selectionChanged(QListViewItem*)), SLOT(changePropertyName(QListViewItem*))); connect(tableNodes,SIGNAL(valueChanged(int,int)),SLOT(changePropertyNodeValue(int,int))); connect(tableEdges,SIGNAL(valueChanged(int,int)),SLOT(changePropertyEdgeValue(int,int))); connect(removeButton , SIGNAL(clicked()) , SLOT(removeProperty()) ); connect(newButton,SIGNAL(clicked()),SLOT(newProperty())); connect(cloneButton,SIGNAL(clicked()),SLOT(cloneProperty())); connect(vScrollNode,SIGNAL(valueChanged(int)),SLOT(scrollNode(int))); connect(vScrollEdge,SIGNAL(valueChanged(int)),SLOT(scrollEdge(int))); GlyphTableString tmp = glWidget->getGlyphTable(); tableNodes->setGlyphTable(tmp); glyphList = new QStringList(); for (GlyphTableString::const_iterator it = tmp.begin(); it != tmp.end(); ++it) { reverseGlyphTable[it->second] = it->first; glyphList->append(it->second.c_str()); } propertySliders = new PropertySlider(this, "propertySlider", true); propertySliders->hide(); } PropertyDialog::~PropertyDialog() { delete glyphList; delete propertySliders; } void PropertyDialog::update (set::iterator itb,set::iterator ite) { for (;itb!=ite;++itb) { #ifndef NDEBUG cerr << " PropertyDialog::Update :objtype =>" << typeid(*(*itb)).name() << endl; #endif if (typeid(*(*itb))==typeid(ClusterTree)) setSuperGraph(((ClusterTree*)(*itb))->getSuperGraph()); } } void PropertyDialog::updateEdges() { if (editedProperty==0) return; SelectionProxy *tmpSel=getProxy(supergraph,"viewSelection"); tableEdges->setNumRows(nbEdge); Iterator *it=supergraph->getEdges(); for (int i=0; it->hasNext();) { char buf[16]; edge tmp=it->next(); if (!_filterSelection || tmpSel->getEdgeValue(tmp)) { if ((i>=vScrollEdgePos-TABLEBUFSIZE/2) && (i<=vScrollEdgePos+TABLEBUFSIZE/2)) { sprintf (buf,"%d", tmp.id ); tableEdges->setText(i,0,buf ); tableEdges->setTulipEdgeItem(editedProperty, editedPropertyName, tmp, i, 1); } else if (i>vScrollEdgePos+TABLEBUFSIZE/2) break; ++i; } } delete it; tableEdges->adjustColumn(0); tableEdges->setColumnWidth(1, tableEdges->horizontalHeader()->width() - tableEdges->columnWidth(0)); } void PropertyDialog::updateNodes() { if (editedProperty==0) return; SelectionProxy *tmpSel=getProxy(supergraph,"viewSelection"); tableNodes->setNumRows(nbNode); Iterator *it=supergraph->getNodes(); for (int i=0; it->hasNext();) { char buf[16]; node tmp=it->next(); if (!_filterSelection || tmpSel->getNodeValue(tmp)) { if ((i>=vScrollNodePos-TABLEBUFSIZE/2) && (i<=vScrollNodePos+TABLEBUFSIZE/2)) { sprintf (buf,"%d", tmp.id ); tableNodes->setText(i,0,buf ); tableNodes->setTulipNodeItem(editedProperty, editedPropertyName, tmp, i, 1); } else if (i>vScrollNodePos+TABLEBUFSIZE/2) break; ++i; } } delete it; tableNodes->adjustColumn(0); tableNodes->setColumnWidth(1, tableNodes->horizontalHeader()->width() - tableNodes->columnWidth(0)); } void PropertyDialog::scrollNode(int i) { if (editedProperty==0) return; // cerr << "scroll node:" << i << endl; //apparement i/20 doit donner la position dans la liste. //si i pas dans notre intervalle on efface tout et on rerempli centré sur i [i-50,i+50] //intervale [i-25,i+25] //il faut donc un index courant; int curId=i/20; // int oldId=vScrollNodePos; bool update=false; if (curId>vScrollNodePos+TABLEBUFSIZE/4) { if (vScrollNodePos+TABLEBUFSIZE/2!=nbNode) { vScrollNodePos=curId; if (curId+TABLEBUFSIZE/2>nbNode) curId=nbNode-TABLEBUFSIZE/2; // cerr << "sortie haute" << " curID" << curId << " nbNode:" << nbNode <vScrollEdgePos+TABLEBUFSIZE/4) { if (vScrollEdgePos+TABLEBUFSIZE/2!=nbEdge) { vScrollEdgePos=curId; if (curId+TABLEBUFSIZE/2>nbEdge) curId=nbEdge-TABLEBUFSIZE/2; // cerr << "sortie haute" << " curID" << curId << " nbNode:" << nbNode <setNumCols(2); tableEdges->setNumCols(2); PProxy *tmpProxy = supergraph->getPropertyProxyContainer()->getProxy(item->text(0).latin1()); editedProperty = tmpProxy; editedPropertyName = item->text(0).latin1(); propertyName->setText(item->text(0)); if (editedPropertyName == "viewSize") { connect(propertySliders->spinBoxX, SIGNAL(valueChanged(int)), this, SLOT(propertySliderValueChanged())); connect(propertySliders->spinBoxY, SIGNAL(valueChanged(int)), this, SLOT(propertySliderValueChanged())); connect(propertySliders->spinBoxZ, SIGNAL(valueChanged(int)), this, SLOT(propertySliderValueChanged())); scaleValuesButton->setEnabled(true); } else { propertySliders->hide(); propertySliders->spinBoxX->disconnect(); propertySliders->spinBoxY->disconnect(); propertySliders->spinBoxZ->disconnect(); propertySliders->resetValues(); scaleValuesButton->setEnabled(false); } if (supergraph->getPropertyProxyContainer()->existLocalProxy(item->text(0).latin1())) inheritedProperties->clearSelection(); else localProperties->clearSelection(); // vScrollNodePos=TABLEBUFSIZE/2; vScrollEdgePos=TABLEBUFSIZE/2; updateNbElements(); // tableNodes->setNumRows(nbNode); // tableEdges->setNumRows(nbEdge); updateNodes(); updateEdges(); } void PropertyDialog::filterSelection(bool b) { _filterSelection= b; updateNbElements(); updateNodes(); updateEdges(); } void PropertyDialog::setNodeValue() { if (editedProperty==0) return; Observable::holdObservers(); bool ok=false; string tmpStr; if (editedPropertyName == "viewShape") { QString shapeName = QInputDialog::getItem(string("Property \"" + editedPropertyName + "\": set all node value").c_str(), "Please choose a shape", *glyphList, 0, false, &ok, this); if (ok) { stringstream ss; ss << reverseGlyphTable[shapeName.latin1()]; tmpStr = ss.str(); } } else if (typeid((*editedProperty)) == typeid(MetricProxy)) { double d = QInputDialog::getDouble(string("Property \"" + editedPropertyName + "\": set all node value").c_str(), "Please enter your value", 0, -2147483647, 2147483647, 10, &ok, this); if (ok) { stringstream ss; ss << d; tmpStr = ss.str(); } } else if (typeid(*editedProperty) == typeid(ColorsProxy)) { QColor color = QColorDialog::getColor(); if (color.isValid()) { stringstream ss; ss << "(" << color.red() << "," << color.green() << "," << color.blue() << ",255)"; tmpStr = ss.str(); ok = true; } } else { QString text = QInputDialog::getText(string("Property \"" + editedPropertyName + "\": set all node value").c_str(), "Please enter your value", QLineEdit::Normal,QString::null, &ok, this); if (ok && !text.isEmpty()) tmpStr = text.latin1(); else ok = false; } if (ok) { bool result=true; SelectionProxy *tmpSel=getProxy(supergraph,"viewSelection"); if (!_filterSelection && supergraph->getPropertyProxyContainer()->existLocalProxy(editedPropertyName)) { result=stringToAllNodeProperty(editedProperty, tmpStr); } else { Iterator *it=supergraph->getNodes(); for (int nbNode=0; it->hasNext();) { node tmp=it->next(); if (!_filterSelection || tmpSel->getNodeValue(tmp)) { result=stringToNodeProperty(editedProperty,tmp,tmpStr); if (!result) break; } if (_filterSelection && tmpSel->getNodeValue(tmp)) { tableNodes->setText(nbNode, 1, tmpStr.c_str()); nbNode++; } } delete it; } if (!result) { QMessageBox::critical(0, "Tulip Property Editor set all node value Failed", QString("The value entered for the nodes is not correct,\n" "The change won't be applied\n") ); } else { updateNodes(); } // inheritedProperties->clearSelection(); // localProperties->clearSelection(); // setSuperGraph(supergraph); } Observable::unholdObservers(); PushButton6->setDown(false); } void PropertyDialog::setEdgeValue() { if (editedProperty==0) return; Observable::holdObservers(); bool ok=false; string tmpStr; if (typeid(*editedProperty) == typeid(ColorsProxy)) { QColor color = QColorDialog::getColor(); if (color.isValid()) { stringstream ss; ss << "(" << color.red() << "," << color.green() << "," << color.blue() << ",255)"; tmpStr = ss.str(); ok = true; } } else { QString text = QInputDialog::getText(string("Property \"" + editedPropertyName + "\": set all edge value").c_str(), "Please enter your value", QLineEdit::Normal, QString::null, &ok, this); if (ok && !text.isEmpty()) tmpStr = text.latin1(); else ok = false; } if (ok) { bool result=true; SelectionProxy *tmpSel=getProxy(supergraph,"viewSelection"); if (!_filterSelection && supergraph->getPropertyProxyContainer()->existLocalProxy(editedPropertyName)) { result=stringToAllEdgeProperty(editedProperty, tmpStr); } else { Iterator *itE=supergraph->getEdges(); for (int nbEdge=0; itE->hasNext();) { edge tmp=itE->next(); if (!_filterSelection || tmpSel->getEdgeValue(tmp)) { result=stringToEdgeProperty(editedProperty, tmp, tmpStr); if (!result) break; } if (_filterSelection && tmpSel->getEdgeValue(tmp)) { tableEdges->setText(nbEdge, 1, tmpStr.c_str()); nbEdge++; } } delete itE; } if (!result) { QMessageBox::critical(0, "Tulip Property Editor set all node value Failed", QString("The value entered for the nodes is not correct,\n" "The change won't be applied\n") ); } else { updateEdges(); } // inheritedProperties->clearSelection(); // localProperties->clearSelection(); // setSuperGraph(supergraph); } PushButton6_2->setDown(false); Observable::unholdObservers(); } void PropertyDialog::selectNode(node n) {} void PropertyDialog::selectEdge(edge e) {} void PropertyDialog::setSuperGraph(SuperGraph *sg) { supergraph = sg; editedProperty = NULL; //Build the property list localProperties->clear(); inheritedProperties->clear(); tableNodes->setNumRows(0); tableNodes->setSuperGraph(sg); tableEdges->setNumRows(0); tableEdges->setSuperGraph(sg); vScrollEdgePos=0;vScrollNodePos=0; vScrollNode->setValue(0);vScrollEdge->setValue(0); vScrollNodePos=TABLEBUFSIZE/2; vScrollEdgePos=TABLEBUFSIZE/2; propertyName->setText(QString("Select a Property")); Iterator *it=sg->getPropertyProxyContainer()->getLocalProperties(); for (;it->hasNext();) { string tmp=it->next(); if (tmp != "outdegree") { QListViewItem *tmpItem = new QListViewItem(localProperties); tmpItem->setText(0,QString(tmp.c_str())); } } delete it; it=sg->getPropertyProxyContainer()->getInheritedProperties(); for (;it->hasNext();) { string tmp=it->next(); if (tmp != "outdegree") { QListViewItem *tmpItem=new QListViewItem(inheritedProperties); tmpItem->setText(0,QString(tmp.c_str())); } } delete it; } void PropertyDialog::newProperty() { QStringList lst; lst << "Selection" << "Metric" << "Layout" << "String" << "Integer" << "Sizes" << "Color"; bool ok = FALSE; QString res = QInputDialog::getItem( "Property type","Please select your property type", lst, 0, false, &ok, this ); if ( ok ) { QString text = QInputDialog::getText( "Property name" , "Please enter the property name" , QLineEdit::Normal, QString::null, &ok, this ); if (ok) { if (text == "outdegree") { QMessageBox::critical(NULL, "Name \"outdegree\" Forbidden", QString("The property name \"outdegree\".\nAborting property creation") ); return; } bool cached,resultBool;string erreurMsg; if (res == "Selection") getLocalProxy(supergraph,text.latin1(),cached,resultBool,erreurMsg); if (res == "Metric") getLocalProxy(supergraph,text.latin1(),cached,resultBool,erreurMsg); if (res == "Layout") getLocalProxy(supergraph,text.latin1(),cached,resultBool,erreurMsg); if (res == "String") getLocalProxy(supergraph,text.latin1(),cached,resultBool,erreurMsg); if (res == "Integer") getLocalProxy(supergraph,text.latin1(),cached,resultBool,erreurMsg); if (res == "Sizes") getLocalProxy(supergraph,text.latin1(),cached,resultBool,erreurMsg); if (res == "Color") getLocalProxy(supergraph,text.latin1(),cached,resultBool,erreurMsg); setSuperGraph(supergraph); glWidget->setSuperGraph(supergraph); } } } void PropertyDialog::removeProperty() { if (editedProperty==0) return; if(supergraph->getPropertyProxyContainer()->existLocalProxy(editedPropertyName)) { supergraph->getPropertyProxyContainer()->delLocalProxy(editedPropertyName); glWidget->setSuperGraph(supergraph); setSuperGraph(supergraph); editedProperty=0; } else QMessageBox::critical( 0, "Tulip Property Editor Remove Failed", QString("You cannot remove an inherited property,\n") ); } void PropertyDialog::cloneProperty() { bool ok=false; QString text = QInputDialog::getText( "Property name" , "Please enter the property name" , QLineEdit::Normal,QString::null, &ok, this ); if (ok) { Observable::holdObservers(); PropertyProxyContainer *propC=supergraph->getPropertyProxyContainer(); if (propC->existProxy(text.latin1())) { if (typeid(*propC->getProxy(text.latin1()))!=typeid(*editedProperty)) { QMessageBox::critical( 0, "Tulip Warning" ,"Property are not of the same type"); return; } } bool cached,resultBool;string erreurMsg; if (typeid((*editedProperty)) == typeid(MetricProxy)) {*getLocalProxy(supergraph,text.latin1())=*((MetricProxy*)editedProperty);} if (typeid((*editedProperty)) == typeid(LayoutProxy)) {*getLocalProxy(supergraph,text.latin1())=*((LayoutProxy*)editedProperty);} if (typeid((*editedProperty)) == typeid(StringProxy)) {*getLocalProxy(supergraph,text.latin1())=*((StringProxy*)editedProperty);} if (typeid((*editedProperty)) == typeid(SelectionProxy)) {*getLocalProxy(supergraph,text.latin1())=*((SelectionProxy*)editedProperty);} if (typeid((*editedProperty)) == typeid(IntProxy)) {*getLocalProxy(supergraph,text.latin1())=*((IntProxy*)editedProperty);} if (typeid((*editedProperty)) == typeid(ColorsProxy)) {*getLocalProxy(supergraph,text.latin1())=*((ColorsProxy*)editedProperty);} if (typeid((*editedProperty)) == typeid(SizesProxy)) {*getLocalProxy(supergraph,text.latin1(),cached,resultBool,erreurMsg)=*((SizesProxy*)editedProperty);} setSuperGraph(supergraph); glWidget->setSuperGraph(supergraph); Observable::unholdObservers(); } } void PropertyDialog::changePropertyEdgeValue(int i,int j) { if (editedProperty==0) return; Observable::holdObservers(); bool result=true; string str=tableEdges->text(i,j).latin1(); SelectionProxy *tmpSel=getProxy(supergraph, "viewSelection"); Iterator *it=supergraph->getEdges(); edge tmp; for (int pos=0; it->hasNext();) { tmp=it->next(); if (!_filterSelection || tmpSel->getEdgeValue(tmp)) { if (pos==i) { result=stringToEdgeProperty(editedProperty,tmp,str); break; } ++pos; } } delete it; if (!result) { QMessageBox::critical( 0, "Tulip Property Editor Change Failed", QString("The value entered for this edge is not correct,\n" "The change won't be applied\n" "Modify the entered value to apply the changes.") ); } else { emit tulipEdgePropertyChanged(supergraph, tmp, editedPropertyName.c_str(), str.c_str()); } tableEdges->setColumnWidth(1, tableEdges->horizontalHeader()->width() - tableNodes->columnWidth(0)); Observable::unholdObservers(); } void PropertyDialog::changePropertyNodeValue(int i,int j) { if (editedProperty==0) return; Observable::holdObservers(); bool result=true; string str=(tableNodes->text(i,j).latin1()); SelectionProxy *tmpSel=getProxy(supergraph, "viewSelection"); Iterator *it=supergraph->getNodes(); node tmp; for (int pos=0; it->hasNext();) { tmp=it->next(); if (!_filterSelection || tmpSel->getNodeValue(tmp)) { if (pos==i) { result=stringToNodeProperty(editedProperty,tmp,str); break; } ++pos; } } delete it; if (!result) { QMessageBox::critical( 0, "Tulip Property Editor Change Failed", QString("The value entered for this node is not correct,\n" "The change won't be applied\n" "Modify the entered value to apply the changes.") ); } else { emit tulipNodePropertyChanged(supergraph, tmp, editedPropertyName.c_str(), str.c_str()); } tableNodes->setColumnWidth(1, tableNodes->horizontalHeader()->width() - tableNodes->columnWidth(0)); Observable::unholdObservers(); } void PropertyDialog::updateNbElements() { if (!_filterSelection) { nbNode=supergraph->numberOfNodes(); nbEdge=supergraph->numberOfEdges(); } else { SelectionProxy *tmpSel=getProxy(supergraph,"viewSelection"); nbNode=0; nbEdge=0; Iterator *it=supergraph->getNodes(); for (;it->hasNext();) { node tmp=it->next(); if (tmpSel->getNodeValue(tmp)) { nbNode++; } } delete it; Iterator *itE=supergraph->getEdges(); for (;itE->hasNext();) { edge tmp=itE->next(); if (tmpSel->getEdgeValue(tmp)) { nbEdge++; } } delete itE; } } void PropertyDialog::scaleValuesClicked() { PropertyProxyContainer *ppc = supergraph->getPropertyProxyContainer(); if (!ppc->existLocalProxy("savedViewSize")) { bool cached, result; string errMsg; *getLocalProxy(supergraph, "savedViewSize", cached, result, errMsg) = *(SizesProxy *)editedProperty; } switch(propertySliders->exec()) { case QDialog::Rejected: *(SizesProxy *)editedProperty = *(SizesProxy *)(ppc->getLocalProxy("savedViewSize")); break; case QDialog::Accepted: break; } ppc->delLocalProxy("savedViewSize"); propertySliders->hide(); } void PropertyDialog::propertySliderValueChanged() { Observable::holdObservers(); SizesProxy *sp = (SizesProxy *) supergraph->getPropertyProxyContainer()->getLocalProxy("savedViewSize"); float x = (100 + propertySliders->spinBoxX->value()) / 100.0; float y = (100 + propertySliders->spinBoxY->value()) / 100.0; float z = (100 + propertySliders->spinBoxZ->value()) / 100.0; Iterator *it = supergraph->getNodes(); while(it->hasNext()) { node n = it->next(); Size s = sp->getNodeValue(n); s[0] = s[0] * x; s[1] = s[1] * y; s[2] = s[2] * z; ((SizesProxy *)editedProperty)->setNodeValue(n, s); } delete it; Observable::unholdObservers(); updateNodes(); glWidget->redraw(); }