void mainWin::slotInstallClicked() { // Sanity check our install choices if (!sanityCheck()) return; // Start the installation doUpdates(); }
void KstDataManagerI::delete_I() { QListViewItem *qi = DataView->selectedItems().at(0); KstObjectItem *koi = static_cast<KstObjectItem*>(qi); if (qi->rtti() == RTTI_OBJ_OBJECT) { doc->removeDataObject(koi->tagName()); } else if (qi->rtti() == RTTI_OBJ_DATA_VECTOR) { KST::vectorList.removeTag(koi->tagName()); doUpdates(); } }
void UpdateThread::run() { bool force; int updateTime; #if UPDATEDEBUG > 0 qDebug() << "Update thread running, tid=" << (int)QThread::currentThread() << endl; #if UPDATEDEBUG > 2 qDebug() << "dataObjectList lock is at " << (void*)(&KST::dataObjectList.lock()) << endl; qDebug() << "dataSourceList lock is at " << (void*)(&KST::dataSourceList.lock()) << endl; #endif #endif _done = false; while (!_done) { _statusMutex.lock(); updateTime = _updateTime; if (_waitCondition.wait(&_statusMutex, _updateTime)) { #if UPDATEDEBUG > 0 qDebug() << "Update timer " << _updateTime << endl; #endif if (!_force) { break; } } if (_done) { _statusMutex.unlock(); break; } force = _force; _force = false; _statusMutex.unlock(); if (_paused && !force) { #if UPDATEDEBUG > 0 qDebug() << "Update thread paused..." << endl; #endif continue; } bool gotData = false; if (doUpdates(force, &gotData) && !_done) { #if UPDATEDEBUG > 1 qDebug() << "Update resulted in: TRUE!" << endl; #endif if (gotData) { qDebug() << "Posting UpdateDataDialogs" << endl; ThreadEvent *e = new ThreadEvent(ThreadEvent::UpdateDataDialogs); e->_curves = _updatedCurves; e->_counter = _updateCounter; QApplication::postEvent(_doc, e); // this event also triggers an implicit repaint } else { QApplication::postEvent(_doc, new ThreadEvent(ThreadEvent::Repaint)); } // Wait for UI thread to finish events. If we don't wait // 1: the UI thread could get flooded with events // 2: the update thread could change vectors during a paint, causing // inconsistent curves to be plotted ie, the X vector updated // and the Y vector not yet updated... // Race warning: Syncronization of updating() is not assured, // but updating() will always return a valid answer which was // true 'close' to when we asked. This will safely keep the // update thread from over filling the UI thread. The usleeps // will hopefully give the UI thread a chance to set itself... usleep(1000); // 1 ms on 2.6 kernel. 10ms on 2.4 kernel while (!_done && _doc->updating()) { // wait for the UI to finish old events usleep(1000); } usleep(1000); // check again... not strictly needed given implicit repaint below, // but it should just return false, so no harm done. while (!_done && _doc->updating()) { usleep(1000); } } else { QApplication::postEvent(_doc, new ThreadEvent(ThreadEvent::NoUpdate)); } } QApplication::postEvent(_doc, new ThreadEvent(ThreadEvent::Done)); }
void KstDataManagerI::delete_I() { QListViewItem *qi = DataView->selectedItems().at(0); if (!qi) { return; } KstObjectItem *koi = static_cast<KstObjectItem*>(qi); if (koi->removable()) { if (qi->rtti() == RTTI_OBJ_OBJECT) { doc->removeDataObject(koi->tag().tag()); } else if (qi->rtti() == RTTI_OBJ_DATA_VECTOR) { KST::vectorList.lock().writeLock(); KST::vectorList.removeTag(koi->tag().tag()); KST::vectorList.lock().unlock(); doUpdates(); } else if (qi->rtti() == RTTI_OBJ_STATIC_VECTOR) { KST::vectorList.lock().writeLock(); KST::vectorList.removeTag(koi->tag().tag()); KST::vectorList.lock().unlock(); doUpdates(); } else if (qi->rtti() == RTTI_OBJ_DATA_MATRIX) { KST::matrixList.lock().writeLock(); KST::matrixList.removeTag(koi->tag().tag()); KST::matrixList.lock().unlock(); doUpdates(); } else if (qi->rtti() == RTTI_OBJ_STATIC_MATRIX) { KST::matrixList.lock().writeLock(); KST::matrixList.removeTag(koi->tag().tag()); KST::matrixList.lock().unlock(); doUpdates(); } update(); } else { // Don't prompt for base curves KstBaseCurvePtr bc = kst_cast<KstBaseCurve>(koi->dataObject()); if (bc || KMessageBox::warningYesNo(this, i18n("There are other objects in memory that depend on %1. Do you wish to delete them too?").arg(koi->tag().tag())) == KMessageBox::Yes) { if (qi->rtti() == RTTI_OBJ_OBJECT) { koi->dataObject()->deleteDependents(); doc->removeDataObject(koi->tag().tag()); } else if (qi->rtti() == RTTI_OBJ_DATA_VECTOR) { KstRVectorPtr x = kst_cast<KstRVector>(*KST::vectorList.findTag(koi->tag().tag())); if (x) { x->deleteDependents(); x = 0L; KST::vectorList.lock().writeLock(); KST::vectorList.removeTag(koi->tag().tag()); KST::vectorList.lock().unlock(); doUpdates(); } else { KMessageBox::sorry(this, i18n("Unknown error deleting data vector.")); } } else if (qi->rtti() == RTTI_OBJ_STATIC_VECTOR) { KstSVectorPtr x = kst_cast<KstSVector>(*KST::vectorList.findTag(koi->tag().tag())); if (x) { x->deleteDependents(); x = 0L; KST::vectorList.lock().writeLock(); KST::vectorList.removeTag(koi->tag().tag()); KST::vectorList.lock().unlock(); doUpdates(); } else { KMessageBox::sorry(this, i18n("Unknown error deleting static vector.")); } } else if (qi->rtti() == RTTI_OBJ_DATA_MATRIX) { KstRMatrixPtr x = kst_cast<KstRMatrix>(*KST::matrixList.findTag(koi->tag().tag())); if (x) { x->deleteDependents(); x = 0L; KST::matrixList.lock().writeLock(); KST::matrixList.removeTag(koi->tag().tag()); KST::matrixList.lock().unlock(); doUpdates(); } else { KMessageBox::sorry(this, i18n("Unknown error deleting data matrix.")); } } else if (qi->rtti() == RTTI_OBJ_STATIC_MATRIX) { KstSMatrixPtr x = kst_cast<KstSMatrix>(*KST::matrixList.findTag(koi->tag().tag())); if (x) { x->deleteDependents(); x = 0L; KST::matrixList.lock().writeLock(); KST::matrixList.removeTag(koi->tag().tag()); KST::matrixList.lock().unlock(); doUpdates(); } else { KMessageBox::sorry(this, i18n("Unknown error deleting static matrix.")); } } KstApp::inst()->paintAll(KstPainter::P_PLOT); update(); } else { KMessageBox::sorry(this, i18n("Cannot delete objects with dependencies.")); } } }
void KstDataManagerI::update() { if (!isShown()) { return; } QListViewItem *currentItem = DataView->selectedItem(); QPtrStack<QListViewItem> trash; KST::dataObjectList.lock().writeLock(); KST::vectorList.lock().writeLock(); KST::matrixList.lock().writeLock(); // garbage collect first for (QListViewItem *i = DataView->firstChild(); i; i = i->nextSibling()) { KstObjectItem *oi = static_cast<KstObjectItem*>(i); if (i->rtti() == RTTI_OBJ_OBJECT) { if (KST::dataObjectList.findTag(oi->tag().tag()) == KST::dataObjectList.end()) { trash.push(i); } } else if (i->rtti() == RTTI_OBJ_DATA_MATRIX || i->rtti() == RTTI_OBJ_MATRIX || i->rtti() == RTTI_OBJ_STATIC_MATRIX) { if (KST::matrixList.findTag(oi->tag().tag()) == KST::matrixList.end()) { trash.push(i); } } else { if (KST::vectorList.findTag(oi->tag().tag()) == KST::vectorList.end()) { trash.push(i); } } } trash.setAutoDelete(true); DataView->blockSignals(true); trash.clear(); DataView->blockSignals(false); // update the data objects for (KstDataObjectList::iterator it = KST::dataObjectList.begin(); it != KST::dataObjectList.end(); ++it) { KstReadLocker dol(*it); bool found = false; for (QListViewItem *i = DataView->firstChild(); i; i = i->nextSibling()) { KstObjectItem *oi = static_cast<KstObjectItem*>(i); if (oi->rtti() == RTTI_OBJ_OBJECT && oi->tag().tag() == (*it)->tag().tag()) { oi->update(); found = true; break; } } if (!found) { KstObjectItem *i = new KstObjectItem(DataView, *it, this); connect(i, SIGNAL(updated()), this, SLOT(doUpdates())); } } KST::dataObjectList.lock().unlock(); // update the data vectors KstRVectorList rvl = kstObjectSubList<KstVector,KstRVector>(KST::vectorList); for (KstRVectorList::iterator it = rvl.begin(); it != rvl.end(); ++it) { KstReadLocker vl(*it); bool found = false; for (QListViewItem *i = DataView->firstChild(); i; i = i->nextSibling()) { KstObjectItem *oi = static_cast<KstObjectItem*>(i); if (oi->rtti() == RTTI_OBJ_DATA_VECTOR && oi->tag().tag() == (*it)->tag().tag()) { oi->update(true, 1); found = true; break; } } if (!found) { KstObjectItem *i = new KstObjectItem(DataView, *it, this, 1); connect(i, SIGNAL(updated()), this, SLOT(doUpdates())); } } // update the static vectors KstSVectorList svl = kstObjectSubList<KstVector,KstSVector>(KST::vectorList); for (KstSVectorList::iterator it = svl.begin(); it != svl.end(); ++it) { KstReadLocker vl(*it); bool found = false; for (QListViewItem *i = DataView->firstChild(); i; i = i->nextSibling()) { KstObjectItem *oi = static_cast<KstObjectItem*>(i); if (oi->rtti() == RTTI_OBJ_STATIC_VECTOR && oi->tag().tag() == (*it)->tag().tag()) { oi->update(true, 1); found = true; break; } } if (!found) { KstObjectItem *i = new KstObjectItem(DataView, *it, this, 1); connect(i, SIGNAL(updated()), this, SLOT(doUpdates())); } } KST::vectorList.lock().unlock(); // update the data matrices KstRMatrixList rml = kstObjectSubList<KstMatrix,KstRMatrix>(KST::matrixList); for (KstRMatrixList::iterator it = rml.begin(); it != rml.end(); ++it) { KstReadLocker ml(*it); bool found = false; for (QListViewItem *i = DataView->firstChild(); i; i = i->nextSibling()) { KstObjectItem *oi = static_cast<KstObjectItem*>(i); if (oi->rtti() == RTTI_OBJ_DATA_MATRIX && oi->tag().tag() == (*it)->tag().tag()) { oi->update(true, 1); found = true; break; } } if (!found) { KstObjectItem *i = new KstObjectItem(DataView, *it, this, 1); connect(i, SIGNAL(updated()), this, SLOT(doUpdates())); } } // update the static matrices KstSMatrixList sml = kstObjectSubList<KstMatrix,KstSMatrix>(KST::matrixList); for (KstSMatrixList::iterator it = sml.begin(); it != sml.end(); ++it) { KstReadLocker ml(*it); bool found = false; for (QListViewItem *i = DataView->firstChild(); i; i = i->nextSibling()) { KstObjectItem *oi = static_cast<KstObjectItem*>(i); if (oi->rtti() == RTTI_OBJ_STATIC_MATRIX && oi->tag().tag() == (*it)->tag().tag()) { oi->update(true, 1); found = true; break; } } if (!found) { KstObjectItem *i = new KstObjectItem(DataView, *it, this, 1); connect(i, SIGNAL(updated()), this, SLOT(doUpdates())); } } KST::matrixList.lock().unlock(); // is this really necessary? I would think not... for (QListViewItem *i = DataView->firstChild(); i; i = i->nextSibling()) { if (i == currentItem) { DataView->setCurrentItem(i); DataView->setSelected(i, true); break; } } if (DataView->selectedItem()) { static_cast<KstObjectItem*>(DataView->currentItem())->updateButtons(); } else { Edit->setEnabled(false); Delete->setEnabled(false); } }
//------------------------------------------------------------------------------ // SOLVE BILATERAL //------------------------------------------------------------------------------ bool PGSImpulseSolver:: solveBilateral (const Array_<MultiplierIndex>& participating, // p<=m of these const Matrix& A, // m X m, symmetric const Vector& D, // m, diag>=0 added to A const Vector& rhs, // m, RHS Vector& pi // m, unknown result ) const { SimTK_DEBUG("--------------------------------\n"); SimTK_DEBUG( "PGS BILATERAL SOLVER:\n"); ++m_nBilateralSolves; const int m=A.nrow(); const int p = (int)participating.size(); assert(A.ncol()==m); assert(D.size()==0 || D.size()==m); assert(rhs.size()==m); assert(p<=m); pi.resize(m); pi.setToZero(); // That takes care of all non-participators. if (p == 0) { SimTK_DEBUG(" no bilateral participators. Nothing to do.\n"); SimTK_DEBUG("--------------------------------\n"); return true; } // Track total error for all included equations, and the error for just // those equations that are being enforced. bool converged = false; Real normRMSenf = Infinity, sor = m_SOR; Real prevNormRMSenf = NaN; int its = 1; Array_<Real> rowSums; // handy temp for (; its <= m_maxIters; ++its) { ++m_nBilateralIters; Real sum2enf = 0; // track solution errors prevNormRMSenf = normRMSenf; // All the participating constraints are unconditionally active. Array_<MultiplierIndex> mults(1); for (int k=0; k < p; ++k) { mults[0] = participating[k]; doRowSums(participating,mults,A,D,pi,rowSums); const Real localEr2=doUpdates(mults,A,D,rhs,sor,rowSums,pi); sum2enf += localEr2; } normRMSenf = std::sqrt(sum2enf/p); const Real rate = normRMSenf/prevNormRMSenf; if (rate > 1) { SimTK_DEBUG3("GOT WORSE@%d: sor=%g rate=%g\n", its, sor, rate); if (sor > .1) sor = std::max(.8*sor, .1); } #ifndef NDEBUG printf("iter %d: EST rmsEnf=%g rate=%g\n", its, normRMSenf, normRMSenf/prevNormRMSenf); #endif if (normRMSenf < m_convergenceTol) //TODO: add failure-to-improve check { SimTK_DEBUG2("BILATERAL PGS converged to %g in %d iters\n", normRMSenf, its); converged = true; break; } #ifndef NDEBUG cout << "pi=" << pi << " err=" << normRMSenf << " rate=" << rate << endl; #endif } if (!converged) { SimTK_DEBUG2("BILATERAL PGS CONVERGENCE FAILURE: %d iters -> norm=%g\n", its, normRMSenf); ++m_nBilateralFail; } #ifndef NDEBUG cout << "A=" << A; cout << "D=" << D << endl; cout << "rhs=" << rhs << endl; cout << "active=" << participating << endl; cout << "-> pi=" << pi << endl; if (D.size()) cout << "resid=" << A*pi+D.elementwiseMultiply(pi)-rhs << endl; else cout << "resid=" << A*pi-rhs << endl; #endif SimTK_DEBUG("--------------------------------\n"); return converged; }
//------------------------------------------------------------------------------ // SOLVE //------------------------------------------------------------------------------ bool PGSImpulseSolver:: solve(int phase, const Array_<MultiplierIndex>& participating, // p<=m of these const Matrix& A, // m X m, symmetric const Vector& D, // m, diag >= 0 added to A const Array_<MultiplierIndex>& expanding, Vector& piExpand, // m Vector& verrStart, // m, in/out Vector& verrApplied, // m Vector& pi, // m, piUnknown Array_<UncondRT>& unconditional, Array_<UniContactRT>& uniContact, // with friction Array_<UniSpeedRT>& uniSpeed, Array_<BoundedRT>& bounded, Array_<ConstraintLtdFrictionRT>& consLtdFriction, Array_<StateLtdFrictionRT>& stateLtdFriction ) const { SimTK_DEBUG("\n-----------------\n"); SimTK_DEBUG( "START PGS SOLVER:\n"); ++m_nSolves[phase]; #ifndef NDEBUG {FactorQTZ fac(A); cout << "A=" << A; cout << "D=" << D; cout << "verrStart=" << verrStart << endl; cout << "verrApplied=" << verrApplied << endl; cout << "expanding mx=" << expanding << endl; cout << "piExpand=" << piExpand << endl; Vector verrDbg, x; verrDbg = verrStart; if (verrApplied.size()) verrDbg += verrApplied; fac.solve(verrDbg, x); cout << "x=" << x << endl; cout << "resid=" << A*x-verrDbg << endl;} #endif const int m=A.nrow(); assert(A.ncol()==m); assert(D.size()==m); assert(verrStart.size()==m); assert(verrApplied.size()==0 || verrApplied.size()==m); assert(piExpand.size()==m); const int p = (int)participating.size(); const int nx = (int)expanding.size(); assert(p<=m); assert(nx<=m); pi.resize(m); pi.setToZero(); // Use this for piUnknown // If there are applied forces, add them to the rhs. if (verrApplied.size()) verrStart += verrApplied; // Move expansion impulse to RHS. We will always apply the full expansion // impulse in one interval in this solver. if (nx) for (MultiplierIndex mx(0); mx < m; ++mx) { verrStart[mx] -= multRowTimesSparseCol(A,mx,expanding,piExpand) + D[mx]*piExpand[mx]; } // Now rhs = verrStart + verrApplied - [A+D]*piExpand. #ifndef NDEBUG printf("PGS::solve(): using verr="); cout << verrStart << endl; #endif // Partitions of selected subset. const int mUncond = (int)unconditional.size(); const int mUniSpeed = (int)uniSpeed.size(); const int mBounded = (int)bounded.size(); // State limited friction has no dependence on unknown multipliers. const int mStateLtd = (int)stateLtdFriction.size(); // Must do unilateral friction and constraint-limited friction last because // they depend on normal multipliers. const int mUniCont = (int)uniContact.size(); const int mConsLtd = (int)consLtdFriction.size(); // If debugging, check for consistent constraint equation count. #ifndef NDEBUG {int mCount = mUniSpeed + mBounded; // 1 each for (int k=0; k<mUncond; ++k) mCount += unconditional[k].m_mults.size(); for (int k=0; k<mUniCont; ++k) { if (uniContact[k].m_type==Observing) continue; // neither normal nor friction participate if (uniContact[k].m_type==Participating) ++mCount; // normal participates if (uniContact[k].hasFriction()) mCount += 2; // friction participates even if normal is Known } for (int k=0; k<mStateLtd; ++k) mCount += stateLtdFriction[k].m_Fk.size(); for (int k=0; k<mConsLtd; ++k) mCount += consLtdFriction[k].m_Fk.size(); assert(mCount == p);} #endif if (p == 0) { SimTK_DEBUG1("PGS %d: nothing to do; converged in 0 iters.\n", phase); // Returning pi=0; can still have piExpand!=0 so verr is updated. return true; } // Track total error for all included equations, and the error for just // those equations that are being enforced. bool converged = false; Real normRMSall = Infinity, normRMSenf = Infinity, sor = m_SOR; Real prevNormRMSenf = NaN; int its = 1; Array_<Real> rowSums; // handy temp for (; its <= m_maxIters; ++its) { ++m_nIters[phase]; Real sum2all = 0, sum2enf = 0; // track solution errors prevNormRMSenf = normRMSenf; // UNCONDITIONAL: these are always on. for (int k=0; k < mUncond; ++k) { const UncondRT& rt = unconditional[k]; doRowSums(participating,rt.m_mults,A,D,pi,rowSums); const Real er2=doUpdates(rt.m_mults,A,D,verrStart,sor,rowSums,pi); sum2all += er2; sum2enf += er2; } // UNILATERAL CONTACT NORMALS. Do all of these before any friction. for (int k=0; k < mUniCont; ++k) { UniContactRT& rt = uniContact[k]; if (rt.m_type != Participating) continue; const MultiplierIndex Nk = rt.m_Nk; const Real rowSum=doRowSum(participating,Nk,A,D,pi); const Real er2=doUpdate(Nk,A,D,verrStart,sor,rowSum,pi); sum2all += er2; rt.m_contactCond = boundUnilateral(rt.m_sign, pi[Nk]); if (rt.m_contactCond == UniActive) sum2enf += er2; } // UNILATERAL CONTACT FRICTION. These are limited by the normal // multiplier or by a known normal force during Poisson expansion. for (int k=0; k < mUniCont; ++k) { UniContactRT& rt = uniContact[k]; if (rt.m_type == Observing || !rt.hasFriction()) continue; const MultiplierIndex Nk = rt.m_Nk; const Array_<MultiplierIndex>& Fk = rt.m_Fk; doRowSums(participating,Fk,A,D,pi,rowSums); const Real er2=doUpdates(Fk,A,D,verrStart,sor,rowSums,pi); sum2all += er2; Real N = std::abs(pi[Nk] + piExpand[Nk]); rt.m_frictionCond=boundVector(rt.m_effMu*N, Fk, pi); if (rt.m_frictionCond==Rolling) sum2enf += er2; } // BOUNDED: conditional scalar constraints with constant bounds // on resulting pi. for (int k=0; k < mBounded; ++k) { BoundedRT& rt = bounded[k]; const MultiplierIndex rx = rt.m_ix; const Real rowSum=doRowSum(participating,rx,A,D,pi); const Real er2=doUpdate(rx,A,D,verrStart,sor,rowSum,pi); sum2all += er2; rt.m_boundedCond=boundScalar(rt.m_lb, pi[rx], rt.m_ub); if (rt.m_boundedCond == Engaged) sum2enf += er2; } // STATE LIMITED FRICTION: a set of constraint equations forming a // vector whose maximum length is limited. for (int k=0; k < mStateLtd; ++k) { StateLtdFrictionRT& rt = stateLtdFriction[k]; const Array_<MultiplierIndex>& Fk = rt.m_Fk; doRowSums(participating,Fk,A,D,pi,rowSums); const Real localEr2=doUpdates(Fk,A,D,verrStart,sor,rowSums,pi); sum2all += localEr2; rt.m_frictionCond=boundVector(rt.m_effMu*rt.m_knownN, Fk, pi); if (rt.m_frictionCond==Rolling) sum2enf += localEr2; } // CONSTRAINT LIMITED FRICTION: a set of constraint equations forming // a vector whose maximum length is limited by the norm of other // multipliers pi. for (int k=0; k < mConsLtd; ++k) { ConstraintLtdFrictionRT& rt = consLtdFriction[k]; const Array_<int>& Fk = rt.m_Fk; // friction components const Array_<int>& Nk = rt.m_Nk; // normal components doRowSums(participating,Fk,A,D,pi,rowSums); const Real localEr2=doUpdates(Fk,A,D,verrStart,sor,rowSums,pi); sum2all += localEr2; rt.m_frictionCond=boundFriction(rt.m_effMu,Nk,Fk,pi); if (rt.m_frictionCond==Rolling) sum2enf += localEr2; } normRMSall = std::sqrt(sum2all/p); normRMSenf = std::sqrt(sum2enf/p); const Real rate = normRMSenf/prevNormRMSenf; if (rate > 1) { SimTK_DEBUG3("GOT WORSE@%d: sor=%g rate=%g\n", its, sor, rate); if (sor > .1) sor = std::max(.8*sor, .1); } #ifndef NDEBUG printf("%d/%d: EST rmsAll=%g rmsEnf=%g rate=%g\n", phase, its, normRMSall, normRMSenf, normRMSenf/prevNormRMSenf); #endif //#ifdef NDEBUG // i.e., NOT debugging (TODO) //if (its > 90) // printf("%d/%d: EST rmsAll=%g rmsEnf=%g rate=%g\n", phase, its, // normRMSall, normRMSenf, // normRMSenf/prevNormRMSenf); //#endif if (normRMSenf < m_convergenceTol) //TODO: add failure-to-improve check { SimTK_DEBUG3("PGS %d converged to %g in %d iters\n", phase, normRMSenf, its); converged = true; break; } #ifndef NDEBUG cout << "pi=" << pi << " err=" << normRMSenf << " rate=" << rate << endl; #endif } if (!converged) { SimTK_DEBUG3("PGS %d CONVERGENCE FAILURE: %d iters -> norm=%g\n", phase, its, normRMSenf); ++m_nFail[phase]; } verrStart -= A*pi; verrStart -= D.elementwiseMultiply(pi); #ifndef NDEBUG cout << "FINAL@" << its << " pi=" << pi << " verr=" << verrStart << " resid=" << normRMSenf << endl; #endif return converged; }
void KstDataManagerI::update() { if (!isShown()) { return; } QPtrStack<QListViewItem> trash; // Garbage collect first for (QListViewItem *i = DataView->firstChild(); i; i = i->nextSibling()) { KstObjectItem *oi = static_cast<KstObjectItem*>(i); if (i->rtti() == RTTI_OBJ_OBJECT) { if (KST::dataObjectList.findTag(oi->tagName()) == KST::dataObjectList.end()) { trash.push(i); } } else { if (KST::vectorList.findTag(oi->tagName()) == KST::vectorList.end()) { trash.push(i); } } } trash.setAutoDelete(true); trash.clear(); for (KstDataObjectList::iterator it = KST::dataObjectList.begin(); it != KST::dataObjectList.end(); ++it) { bool found = false; for (QListViewItem *i = DataView->firstChild(); i; i = i->nextSibling()) { KstObjectItem *oi = static_cast<KstObjectItem*>(i); if (oi->rtti() == RTTI_OBJ_OBJECT && oi->tagName() == (*it)->tagName()) { oi->update(); found = true; break; } } if (!found) { KstObjectItem *i = new KstObjectItem(DataView, *it, this); connect(i, SIGNAL(updated()), this, SLOT(doUpdates())); } } KstRVectorList rvl = kstObjectSubList<KstVector,KstRVector>(KST::vectorList); for (KstRVectorList::iterator it = rvl.begin(); it != rvl.end(); ++it) { bool found = false; for (QListViewItem *i = DataView->firstChild(); i; i = i->nextSibling()) { KstObjectItem *oi = static_cast<KstObjectItem*>(i); if (oi->rtti() == RTTI_OBJ_DATA_VECTOR && oi->tagName() == (*it)->tagName()) { oi->update(); found = true; break; } } if (!found) { KstObjectItem *i = new KstObjectItem(DataView, *it, this); connect(i, SIGNAL(updated()), this, SLOT(doUpdates())); } } if (DataView->selectedItem()) { static_cast<KstObjectItem*>(DataView->currentItem())->updateButtons(); } else { Edit->setEnabled(false); Delete->setEnabled(false); } }