root/src/xtalopt/ui/tab_progress.cpp @ b4c5e030e854f3acd801d0cc71b9797ac6e5f0c9

Revision b4c5e030e854f3acd801d0cc71b9797ac6e5f0c9, 25.3 KB (checked in by David C. Lonie <loniedavid@…>, 20 months ago)

Clean up logic in progress table's context menu.

  • Property mode set to 100644
Line 
1/**********************************************************************
2  XtalOpt - Tools for advanced crystal optimization
3
4  Copyright (C) 2009-2011 by David Lonie
5
6  This library is free software; you can redistribute it and/or modify
7  it under the terms of the GNU Library General Public License as
8  published by the Free Software Foundation; either version 2.1 of the
9  License, or (at your option) any later version.
10
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 ***********************************************************************/
16
17#include <xtalopt/ui/tab_progress.h>
18
19#include <globalsearch/optimizer.h>
20#include <globalsearch/ui/abstracttab.h>
21
22#include <xtalopt/xtalopt.h>
23#include <xtalopt/ui/dialog.h>
24
25#include <QtGui/QFileDialog>
26#include <QtCore/QTimer>
27#include <QtCore/QSettings>
28#include <QtCore/QMutexLocker>
29#include <QtCore/QtConcurrentRun>
30
31#include <QtGui/QMenu>
32#include <QtGui/QInputDialog>
33
34using namespace GlobalSearch;
35
36namespace XtalOpt {
37
38  TabProgress::TabProgress( XtalOptDialog *parent, XtalOpt *p ) :
39    AbstractTab(parent, p),
40    m_timer(new QTimer (this)),
41    m_mutex(new QMutex),
42    m_update_mutex(new QMutex),
43    m_update_all_mutex(new QMutex),
44    m_context_mutex(new QMutex),
45    m_context_xtal(0)
46  {
47    // Allow queued connections to work with the TableEntry struct
48    qRegisterMetaType<XO_Prog_TableEntry>("XO_Prog_TableEntry");
49
50    ui.setupUi(m_tab_widget);
51
52    QHeaderView *horizontal = ui.table_list->horizontalHeader();
53    horizontal->setResizeMode(QHeaderView::ResizeToContents);
54
55    rowTracking = true;
56
57    // dialog connections
58    connect(m_dialog, SIGNAL(moleculeChanged(GlobalSearch::Structure*)),
59            this, SLOT(highlightXtal(GlobalSearch::Structure*)));
60    connect(m_opt, SIGNAL(sessionStarted()),
61            this, SLOT(startTimer()));
62
63    // Progress table connections
64    connect(m_timer, SIGNAL(timeout()),
65            this, SLOT(updateProgressTable()));
66    connect(ui.push_refresh, SIGNAL(clicked()),
67            this, SLOT(startTimer()));
68    connect(ui.push_refresh, SIGNAL(clicked()),
69            this, SLOT(updateProgressTable()));
70    connect(ui.spin_period, SIGNAL(editingFinished()),
71            this, SLOT(updateProgressTable()));
72    connect(ui.table_list, SIGNAL(currentCellChanged(int,int,int,int)),
73            this, SLOT(selectMoleculeFromProgress(int,int,int,int)));
74    connect(m_opt->tracker(), SIGNAL(newStructureAdded(GlobalSearch::Structure*)),
75            this, SLOT(addNewEntry()),
76            Qt::QueuedConnection);
77    connect(m_opt->queue(), SIGNAL(structureUpdated(GlobalSearch::Structure*)),
78            this, SLOT(newInfoUpdate(GlobalSearch::Structure *)));
79    connect(this, SIGNAL(infoUpdate()),
80            this, SLOT(updateInfo()));
81    connect(ui.table_list, SIGNAL(customContextMenuRequested(QPoint)),
82            this, SLOT(progressContextMenu(QPoint)));
83    connect(ui.push_refreshAll, SIGNAL(clicked()),
84            this, SLOT(updateAllInfo()));
85    connect(m_opt, SIGNAL(refreshAllStructureInfo()),
86            this, SLOT(updateAllInfo()));
87    connect(m_opt, SIGNAL(startingSession()),
88            this, SLOT(disableRowTracking()));
89    connect(m_opt, SIGNAL(sessionStarted()),
90            this, SLOT(enableRowTracking()));
91    connect(this, SIGNAL(updateTableEntry(int, const XO_Prog_TableEntry&)),
92            this, SLOT(setTableEntry(int, const XO_Prog_TableEntry&)));
93
94    initialize();
95  }
96
97  TabProgress::~TabProgress()
98  {
99    delete m_mutex;
100    delete m_update_mutex;
101    delete m_update_all_mutex;
102    delete m_context_mutex;
103    delete m_timer;
104  }
105
106  void TabProgress::writeSettings(const QString &filename)
107  {
108    SETTINGS(filename);
109    const int VERSION = 1;
110    settings->beginGroup("xtalopt/progress");
111    settings->setValue("version",     VERSION);
112    settings->setValue("refreshTime", ui.spin_period->value());
113    settings->endGroup();
114    DESTROY_SETTINGS(filename);
115  }
116
117  void TabProgress::readSettings(const QString &filename)
118  {
119    SETTINGS(filename);
120    settings->beginGroup("xtalopt/progress");
121    int loadedVersion = settings->value("version", 0).toInt();
122    ui.spin_period->setValue(settings->value("refreshTime", 1).toInt());
123    settings->endGroup();
124
125    // Update config data
126    switch (loadedVersion) {
127    case 0:
128    case 1:
129    default:
130      break;
131    }
132
133  }
134
135  void TabProgress::disconnectGUI()
136  {
137    m_timer->disconnect();
138    ui.push_refresh->disconnect();
139    ui.push_refreshAll->disconnect();
140    ui.spin_period->disconnect();
141    ui.table_list->disconnect();
142    disconnect(m_opt->tracker(), 0, this, 0);
143    disconnect(m_opt->queue(), 0, this, 0);
144    disconnect(m_dialog, 0, this, 0);
145    this->disconnect();
146  }
147
148  void TabProgress::updateProgressTable()
149  {
150    // Only allow one update at a time
151    if (!m_update_mutex->tryLock()) {
152      qDebug() << "Killing extra TabProgress::updateProgressTable() call";
153      return;
154    }
155
156    QList<Structure*> running = m_opt->queue()->getAllRunningStructures();
157
158    for (QList<Structure*>::iterator
159           it = running.begin(),
160           it_end = running.end();
161         it != it_end;
162         ++it) {
163      newInfoUpdate(*it);
164    }
165
166    m_update_mutex->unlock();
167  }
168
169  void TabProgress::addNewEntry()
170  {
171    // Prevent XtalOpt threads from modifying the table
172    QMutexLocker locker (m_mutex);
173
174    // The new entry will be at the end of the table, so determine the index:
175    int index = ui.table_list->rowCount();
176    m_opt->tracker()->lockForRead();
177    Xtal *xtal = qobject_cast<Xtal*>(m_opt->tracker()->at(index));
178    m_opt->tracker()->unlock();
179    //qDebug() << "TabProgress::addNewEntry() at index " << index;
180
181    // Turn off signals
182    ui.table_list->blockSignals(true);
183
184    // Store current index for later. If -1, this will be re-set at the end of table
185    int currentInd = ui.table_list->currentRow();
186    if (currentInd >= ui.table_list->rowCount() - 1) currentInd = -1;
187
188    // Add the new row
189    ui.table_list->insertRow(index);
190    // Columns: once for each column in ProgressColumns:
191    for (int i = 0; i < 9; i++) {
192      ui.table_list->setItem(index, i, new QTableWidgetItem());
193    }
194
195    m_infoUpdateTracker.lockForWrite();
196    m_infoUpdateTracker.append(xtal);
197    m_infoUpdateTracker.unlock();
198    locker.unlock();
199    XO_Prog_TableEntry e;
200    xtal->lock()->lockForRead();
201    e.elapsed = xtal->getOptElapsed();
202    e.gen     = xtal->getGeneration();
203    e.id      = xtal->getIDNumber();
204    e.parents = xtal->getParents();
205    e.jobID   = xtal->getJobID();
206    e.volume  = xtal->getVolume();
207    e.status  = "Waiting for data...";
208    e.brush   = QBrush (Qt::white);
209    e.spg     = QString::number( xtal->getSpaceGroupNumber()) + ": "
210      + xtal->getSpaceGroupSymbol();
211
212    if (xtal->hasEnthalpy() || xtal->getEnergy() != 0)
213      e.enthalpy = xtal->getEnthalpy();
214    else
215      e.enthalpy = 0.0;
216    xtal->lock()->unlock();
217
218    ui.table_list->blockSignals(false);
219
220    if (currentInd < 0) currentInd = index;
221    if (rowTracking) ui.table_list->setCurrentCell(currentInd, 0);
222
223    locker.unlock();
224
225    setTableEntry(index, e);
226    emit infoUpdate();
227  }
228
229  void TabProgress::updateAllInfo()
230  {
231    if (!m_update_all_mutex->tryLock()) {
232      qDebug() << "Killing extra TabProgress::updateAllInfo() call";
233      return;
234    }
235    m_opt->tracker()->lockForRead();
236    m_infoUpdateTracker.lockForWrite();
237    QList<Structure*> *structures = m_opt->tracker()->list();
238    for (int i = 0; i < ui.table_list->rowCount(); i++) {
239      m_infoUpdateTracker.append(structures->at(i));
240      emit infoUpdate();
241    }
242    m_infoUpdateTracker.unlock();
243    m_opt->tracker()->unlock();
244    m_update_all_mutex->unlock();
245  }
246
247  void TabProgress::newInfoUpdate(Structure *s)
248  {
249    m_infoUpdateTracker.lockForWrite();
250    if (m_infoUpdateTracker.append(s)) {
251      emit infoUpdate();
252    }
253    m_infoUpdateTracker.unlock();
254  }
255
256  void TabProgress::updateInfo()
257  {
258    if (m_infoUpdateTracker.size() == 0) {
259      return;
260    }
261
262    // Don't update while a context operation is in the works
263    if (m_context_xtal !=0) {
264      qDebug() << "TabProgress::updateInfo: Waiting for context operation to complete (" << m_context_xtal << ") Trying again very soon.";
265      QTimer::singleShot(1000, this, SLOT(updateInfo()));
266      return;
267    }
268
269    QtConcurrent::run(this, &TabProgress::updateInfo_);
270    return;
271  }
272
273  void TabProgress::updateInfo_()
274  {
275    // Prep variables
276    Structure *structure;
277    m_infoUpdateTracker.lockForWrite();
278    if (!m_infoUpdateTracker.popFirst(structure)) {
279      m_infoUpdateTracker.unlock();
280      return;
281    }
282    m_infoUpdateTracker.unlock();
283
284    m_opt->tracker()->lockForRead();
285    int i = m_opt->tracker()->list()->indexOf(structure);
286    m_opt->tracker()->unlock();
287
288    Xtal *xtal = qobject_cast<Xtal*>(structure);
289
290    if (i < 0 || i > ui.table_list->rowCount() - 1) {
291      qDebug() << "TabProgress::updateInfo: Trying to update an index that doesn't exist...yet: ("
292               << i << ") Waiting...";
293      m_infoUpdateTracker.lockForWrite();
294      m_infoUpdateTracker.append(xtal);
295      m_infoUpdateTracker.unlock();
296      QTimer::singleShot(100, this, SLOT(updateInfo()));
297      return;
298    }
299
300    XO_Prog_TableEntry e;
301    uint totalOptSteps = m_opt->optimizer()->getNumberOfOptSteps();
302    e.brush = QBrush (Qt::white);
303
304    QReadLocker xtalLocker (xtal->lock());
305    e.elapsed = xtal->getOptElapsed();
306    e.gen     = xtal->getGeneration();
307    e.id      = xtal->getIDNumber();
308    e.parents = xtal->getParents();
309    e.jobID   = xtal->getJobID();
310    e.volume  = xtal->getVolume();
311    e.spg     = QString::number( xtal->getSpaceGroupNumber()) + ": "
312      + xtal->getSpaceGroupSymbol();
313
314    if (xtal->hasEnthalpy() || xtal->getEnergy() != 0)
315      e.enthalpy = xtal->getEnthalpy();
316    else
317      e.enthalpy = 0.0;
318
319    switch (xtal->getStatus()) {
320    case Xtal::InProcess: {
321      xtalLocker.unlock();
322      QueueInterface::QueueStatus state = m_opt->queueInterface()->getStatus(xtal);
323      xtalLocker.relock();
324      switch (state) {
325      case QueueInterface::Running:
326        e.status = tr("Running (Opt Step %1 of %2, %3 failures)")
327          .arg(QString::number(xtal->getCurrentOptStep()))
328          .arg(QString::number(totalOptSteps))
329          .arg(QString::number(xtal->getFailCount()));
330        e.brush.setColor(Qt::green);
331        break;
332      case QueueInterface::Queued:
333        e.status = tr("Queued (Opt Step %1 of %2, %3 failures)")
334          .arg(QString::number(xtal->getCurrentOptStep()))
335          .arg(QString::number(totalOptSteps))
336          .arg(QString::number(xtal->getFailCount()));
337        e.brush.setColor(Qt::cyan);
338        break;
339      case QueueInterface::Success:
340        e.status = "Starting update...";
341        break;
342      case QueueInterface::Unknown:
343        e.status = "Unknown";
344        e.brush.setColor(Qt::red);
345        break;
346      case QueueInterface::Error:
347        e.status = "Error: Restarting job...";
348        e.brush.setColor(Qt::darkRed);
349        break;
350      case QueueInterface::CommunicationError:
351        e.status = "Communication Error";
352        e.brush.setColor(Qt::darkRed);
353        break;
354      // Shouldn't happen; started and pending only occur when xtal is "Submitted"
355      case QueueInterface::Started:
356      case QueueInterface::Pending:
357      default:
358        break;
359      }
360      break;
361    }
362    case Xtal::Submitted:
363      e.status = tr("Job submitted (%1 of %2)")
364        .arg(QString::number(xtal->getCurrentOptStep()))
365        .arg(QString::number(totalOptSteps));
366      e.brush.setColor(Qt::cyan);
367      break;
368    case Xtal::Restart:
369      e.status = "Restarting job...";
370      e.brush.setColor(Qt::cyan);
371      break;
372    case Xtal::Killed:
373    case Xtal::Removed:
374      e.status = "Killed";
375      e.brush.setColor(Qt::darkGray);
376      break;
377    case Xtal::Duplicate:
378      e.status = tr("Duplicate of %1")
379        .arg(xtal->getDuplicateString());
380      e.brush.setColor(Qt::darkGreen);
381      break;
382    case Xtal::StepOptimized:
383      e.status = "Checking status...";
384      e.brush.setColor(Qt::cyan);
385      break;
386    case Xtal::Optimized:
387      e.status = "Optimized";
388      e.brush.setColor(Qt::yellow);
389      break;
390    case Xtal::WaitingForOptimization:
391      e.status = tr("Waiting for Optimization (%1 of %2)")
392        .arg(QString::number(xtal->getCurrentOptStep()))
393        .arg(QString::number(totalOptSteps));
394      e.brush.setColor(Qt::darkCyan);
395      break;
396    case Xtal::Error:
397      e.status = "Job failed";
398      e.brush.setColor(Qt::red);
399      break;
400    case Xtal::Updating:
401      e.status = "Updating structure...";
402      e.brush.setColor(Qt::cyan);
403      break;
404    case Xtal::Empty:
405      e.status = "Structure empty...";
406      break;
407    }
408
409    if (xtal->getFailCount() != 0) {
410      e.brush.setColor(Qt::red);
411    }
412    emit updateTableEntry(i, e);
413  }
414
415  void TabProgress::setTableEntry(int row, const XO_Prog_TableEntry & e)
416  {
417    // Lock the table
418    QMutexLocker locker (m_mutex);
419
420    ui.table_list->item(row, TimeElapsed)->setText(e.elapsed);
421    ui.table_list->item(row, Gen)->setText(QString::number(e.gen));
422    ui.table_list->item(row, Mol)->setText(QString::number(e.id));
423    ui.table_list->item(row, Ancestry)->setText(e.parents);
424    ui.table_list->item(row, SpaceGroup)->setText(e.spg);
425    ui.table_list->item(row, Volume)->setText(QString::number(e.volume,'f',2));
426    ui.table_list->item(row, Status)->setText(e.status);
427    ui.table_list->item(row, Status)->setBackground(e.brush);
428
429    if (e.jobID)
430      ui.table_list->item(row, JobID)->setText(QString::number(e.jobID));
431    else
432      ui.table_list->item(row, JobID)->setText("N/A");
433
434    if (e.enthalpy != 0)
435      ui.table_list->item(row, Enthalpy)->setText(QString::number(e.enthalpy));
436    else
437      ui.table_list->item(row, Enthalpy)->setText("N/A");
438  }
439
440  void TabProgress::selectMoleculeFromProgress(int row,int,int oldrow,int)
441  {
442    Q_UNUSED(oldrow);
443    if (m_opt->isStarting) {
444      qDebug() << "TabProgress::selectMoleculeFromProgress: Not updating widget while session is starting";
445      return;
446    }
447    if ( row == -1 ) return;
448    emit moleculeChanged(qobject_cast<Xtal*>(m_opt->tracker()->at(row)));
449  }
450
451  void TabProgress::highlightXtal(Structure *s)
452  {
453    Xtal *xtal = qobject_cast<Xtal*>(s);
454    xtal->lock()->lockForRead();
455    int gen = xtal->getGeneration();
456    int id  = xtal->getIDNumber();
457    xtal->lock()->unlock();
458    for (int row = 0; row < ui.table_list->rowCount(); row++) {
459      if (ui.table_list->item(row, Gen)->text().toInt() == gen &&
460          ui.table_list->item(row, Mol)->text().toInt() == id) {
461        ui.table_list->blockSignals(true);
462        ui.table_list->setCurrentCell(row, 0);
463        ui.table_list->blockSignals(false);
464        return;
465      }
466    }
467    // If not found, clear selection
468    ui.table_list->blockSignals(true);
469    ui.table_list->setCurrentCell(-1, -1);
470    ui.table_list->blockSignals(false);
471  }
472
473
474  void TabProgress::startTimer()
475  {
476    if (m_timer->isActive())
477      m_timer->stop();
478    m_timer->start(ui.spin_period->value() * 1000);
479  }
480
481  void TabProgress::stopTimer()
482  {
483    m_timer->stop();
484  }
485
486  void TabProgress::progressContextMenu(QPoint p)
487  {
488    if (m_context_xtal) return;
489    // m_context_mutex prevents multiple menus from appearing, which
490    // ultimately prevents m_context_xtal from being cleared.
491    if (!m_context_mutex->tryLock(100)) {
492      return;
493    }
494
495    QTableWidgetItem *item = ui.table_list->itemAt(p);
496    bool xtalIsSelected = true;
497    int index = -1;
498    if (item == NULL) {
499      xtalIsSelected = false;
500    }
501    else {
502      index = item->row();
503    }
504
505    // Used to determine available options:
506    bool canGenerateOffspring =
507        (this->m_opt->queue()->getAllOptimizedStructures().size() >= 3);
508
509    qDebug() << "Context menu at row " << index;
510
511    // Set m_context_xtal after locking to avoid threading issues.
512    Xtal *xtal = NULL;
513    if (index != -1) {
514      xtal = qobject_cast<Xtal*>(m_opt->tracker()->at(index));
515    }
516
517    bool isKilled = false;
518    if (xtal != NULL) {
519      xtal->lock()->lockForRead();
520      m_context_xtal = xtal;
521
522      Xtal::State state = m_context_xtal->getStatus();
523      isKilled = (state == Xtal::Killed || state == Xtal::Removed);
524
525      xtal->lock()->unlock();
526    }
527
528    QMenu menu;
529    QAction *a_restart  = menu.addAction("&Restart job");
530    QAction *a_kill     = menu.addAction("&Kill structure");
531    QAction *a_unkill   = menu.addAction("Un&kill structure");
532    QAction *a_resetFail = menu.addAction("Reset &failure count");
533    menu.addSeparator();
534    QAction *a_randomize = menu.addAction("Replace with &new random structure");
535    QAction *a_offspring = menu.addAction("Replace with new &offspring");
536    menu.addSeparator();
537    QAction *a_injectSeed= menu.addAction("Inject &seed structure");
538    menu.addSeparator();
539    QAction *a_clipPOSCAR= menu.addAction("&Copy POSCAR to clipboard");
540
541    // Connect actions
542    connect(a_restart, SIGNAL(triggered()), this, SLOT(restartJobProgress()));
543    connect(a_kill, SIGNAL(triggered()), this, SLOT(killXtalProgress()));
544    connect(a_unkill, SIGNAL(triggered()), this, SLOT(unkillXtalProgress()));
545    connect(a_resetFail, SIGNAL(triggered()),
546            this, SLOT(resetFailureCountProgress()));
547    connect(a_randomize, SIGNAL(triggered()),
548            this, SLOT(randomizeStructureProgress()));
549    connect(a_offspring, SIGNAL(triggered()),
550            this, SLOT(replaceWithOffspringProgress()));
551    connect(a_injectSeed, SIGNAL(triggered()),
552            this, SLOT(injectStructureProgress()));
553    connect(a_clipPOSCAR, SIGNAL(triggered()), this,
554            SLOT(clipPOSCARProgress()));
555
556    // Disable / hide illogical operations
557    if (isKilled) {
558      a_kill->setVisible(false);
559      a_restart->setVisible(false);
560    }
561    else {
562      a_unkill->setVisible(false);
563    }
564
565    if (!canGenerateOffspring) {
566      a_offspring->setDisabled(true);
567    }
568
569    if (!xtalIsSelected) {
570      a_restart->setEnabled(false);
571      a_kill->setEnabled(false);
572      a_unkill->setEnabled(false);
573      a_resetFail->setEnabled(false);
574      a_randomize->setEnabled(false);
575      a_offspring->setEnabled(false);
576      a_injectSeed->setEnabled(true);
577      a_clipPOSCAR->setEnabled(false);
578    }
579
580    QAction *selection = menu.exec(QCursor::pos());
581
582    if (selection == 0) {
583      m_context_xtal = 0;
584      m_context_mutex->unlock();
585      return;
586    }
587
588    a_restart->disconnect();
589    a_kill->disconnect();
590    a_unkill->disconnect();
591    a_resetFail->disconnect();
592    if (canGenerateOffspring) {
593      a_offspring->disconnect();
594    }
595    a_injectSeed->disconnect();
596    a_randomize->disconnect();
597
598    m_context_mutex->unlock();
599  }
600
601  void TabProgress::restartJobProgress()
602  {
603    if (!m_context_xtal) return;
604
605    // Get info from xtal
606    m_context_xtal->lock()->lockForRead();
607    int gen = m_context_xtal->getGeneration();
608    int id = m_context_xtal->getIDNumber();
609    int optstep = m_context_xtal->getCurrentOptStep();
610    m_context_xtal->lock()->unlock();
611
612    // Choose which OptStep to use
613    bool ok;
614    int optStep = QInputDialog::getInt(m_dialog,
615                                       tr("Restart Optimization %1x%2")
616                                       .arg(gen)
617                                       .arg(id),
618                                       "Select optimization step to restart from:",
619                                       optstep,
620                                       1,
621                                       m_opt->optimizer()->getNumberOfOptSteps(),
622                                       1,
623                                       &ok);
624    if (!ok) {
625      m_context_xtal = 0;
626      return;
627    }
628    emit startingBackgroundProcessing();
629    QtConcurrent::run(this, &TabProgress::restartJobProgress_, optStep);
630  }
631
632  void TabProgress::restartJobProgress_(int optStep)
633  {
634    QWriteLocker locker (m_context_xtal->lock());
635    m_context_xtal->setCurrentOptStep(optStep);
636
637    m_context_xtal->setStatus(Xtal::Restart);
638    newInfoUpdate(m_context_xtal);
639
640    // Clear context xtal pointer
641    emit finishedBackgroundProcessing();
642    locker.unlock();
643    m_context_xtal = 0;
644  }
645
646  void TabProgress::killXtalProgress()
647  {
648    emit startingBackgroundProcessing();
649    QtConcurrent::run(this, &TabProgress::killXtalProgress_);
650  }
651
652  void TabProgress::killXtalProgress_()
653  {
654    if (!m_context_xtal) {
655      emit finishedBackgroundProcessing();
656      return;
657    }
658
659    // QueueManager will handle mutex locking
660    m_opt->queue()->killStructure(m_context_xtal);
661
662    // Clear context xtal pointer
663    emit finishedBackgroundProcessing();
664    newInfoUpdate(m_context_xtal);
665    m_context_xtal = 0;
666  }
667
668  void TabProgress::unkillXtalProgress()
669  {
670    emit startingBackgroundProcessing();
671    QtConcurrent::run(this, &TabProgress::unkillXtalProgress_);
672  }
673
674  void TabProgress::unkillXtalProgress_()
675  {
676    if (!m_context_xtal) {
677      emit finishedBackgroundProcessing();
678      return;
679    }
680
681    QWriteLocker locker (m_context_xtal->lock());
682    if (m_context_xtal->getStatus() != Xtal::Killed &&
683        m_context_xtal->getStatus() != Xtal::Removed ) {
684      emit finishedBackgroundProcessing();
685      return;
686    }
687
688    // Setting status to Xtal::Error will restart the job if was killed
689    if (m_context_xtal->getStatus() == Xtal::Killed)
690      m_context_xtal->setStatus(Xtal::Error);
691    // Set status to Optimized if xtal was previously optimized
692    else if (m_context_xtal->getStatus() == Xtal::Removed)
693      m_context_xtal->setStatus(Xtal::Optimized);
694
695    // Clear context xtal pointer
696    emit finishedBackgroundProcessing();
697    newInfoUpdate(m_context_xtal);
698    locker.unlock();
699    m_context_xtal = 0;
700  }
701
702  void TabProgress::resetFailureCountProgress()
703  {
704    emit startingBackgroundProcessing();
705    QtConcurrent::run(this, &TabProgress::resetFailureCountProgress_);
706  }
707
708  void TabProgress::resetFailureCountProgress_()
709  {
710    if (!m_context_xtal) {
711      emit finishedBackgroundProcessing();
712      return;
713    }
714
715    QWriteLocker locker (m_context_xtal->lock());
716
717    m_context_xtal->resetFailCount();
718
719    // Clear context xtal pointer
720    emit finishedBackgroundProcessing();
721    newInfoUpdate(m_context_xtal);
722    locker.unlock();
723    m_context_xtal = 0;
724  }
725
726  void TabProgress::randomizeStructureProgress()
727  {
728    emit startingBackgroundProcessing();
729    QtConcurrent::run(this, &TabProgress::randomizeStructureProgress_);
730  }
731
732  void TabProgress::randomizeStructureProgress_()
733  {
734    if (!m_context_xtal) {
735      emit finishedBackgroundProcessing();
736      return;
737    }
738
739    // End job if currently running
740    if (m_context_xtal->getJobID()) {
741      m_opt->queueInterface()->stopJob(m_context_xtal);
742    }
743
744    m_opt->replaceWithRandom(m_context_xtal, "manual");
745
746    // Restart job:
747    newInfoUpdate(m_context_xtal);
748    restartJobProgress_(1);
749    // above function handles background processing signal
750  }
751
752  void TabProgress::replaceWithOffspringProgress()
753  {
754    emit startingBackgroundProcessing();
755    QtConcurrent::run(this, &TabProgress::replaceWithOffspringProgress_);
756  }
757
758  void TabProgress::replaceWithOffspringProgress_()
759  {
760    if (!m_context_xtal) {
761      emit finishedBackgroundProcessing();
762      return;
763    }
764
765    // End job if currently running
766    if (m_context_xtal->getJobID()) {
767      m_opt->queueInterface()->stopJob(m_context_xtal);
768    }
769
770    XtalOpt *xtalopt = qobject_cast<XtalOpt*>(m_opt);
771    Q_ASSERT_X(xtalopt != NULL, Q_FUNC_INFO, "m_opt is not an instance of "
772               "XtalOpt.");
773
774    xtalopt->replaceWithOffspring(m_context_xtal, "manual");
775
776    // Restart job:
777    newInfoUpdate(m_context_xtal);
778    restartJobProgress_(1);
779    // above function handles background processing signal
780  }
781
782  void TabProgress::injectStructureProgress()
783  {
784    // It doesn't matter what xtal was selected
785    m_context_xtal = NULL;
786
787    // Prompt for filename
788    QSettings settings; // Already set up in avogadro/src/main.cpp
789    QString filename = settings.value("xtalopt/opt/seedPath",
790                                      m_opt->filePath).toString();
791
792    // Launch file dialog
793    QFileDialog dialog (m_dialog,
794                        QString("Select structure file to use as seed"),
795                        filename,
796                        "Common formats (*POSCAR *CONTCAR *.got *.cml *cif"
797                        " *.out);;All Files (*)");
798    dialog.selectFile(filename);
799    dialog.setFileMode(QFileDialog::ExistingFile);
800    if (dialog.exec())
801      filename = dialog.selectedFiles().first();
802    else { return;} // User cancel file selection.
803
804    settings.setValue("xtalopt/opt/seedPath", filename);
805
806    // Load in background
807    QtConcurrent::run(this, &TabProgress::injectStructureProgress_,
808                      filename);
809  }
810
811  void TabProgress::injectStructureProgress_(const QString & filename)
812  {
813    XtalOpt *xtalopt = qobject_cast<XtalOpt*>(m_opt);
814    xtalopt->addSeed(filename);
815  }
816
817  void TabProgress::clipPOSCARProgress()
818  {
819    emit startingBackgroundProcessing();
820    QtConcurrent::run(this, &TabProgress::clipPOSCARProgress_);
821  }
822
823  void TabProgress::clipPOSCARProgress_()
824  {
825    if (!m_context_xtal) {
826      emit finishedBackgroundProcessing();
827      return;
828    }
829    QReadLocker locker (m_context_xtal->lock());
830
831    QString poscar = qobject_cast<XtalOpt*>(m_opt)->
832      interpretTemplate("%POSCAR%", m_context_xtal);
833
834    m_opt->setClipboard(poscar);
835
836    // Clear context xtal pointer
837    emit finishedBackgroundProcessing();
838    locker.unlock();
839    m_context_xtal = 0;
840  }
841}
Note: See TracBrowser for help on using the browser.