/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010-2012 University of Bonn. All rights reserved. * * * This file is part of MoleCuilder. * * MoleCuilder is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * MoleCuilder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MoleCuilder. If not, see . */ /* * QtStatusBar.cpp * * Created on: Feb 17, 2010 * Author: crueger */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "QtStatusBar.hpp" //#include "CodePatterns/MemDebug.hpp" #include "CodePatterns/Observer/Notification.hpp" #include "World.hpp" #include "Actions/ActionQueue.hpp" #include "Actions/ActionStatusList.hpp" #include "Actions/Process.hpp" #define PLURAL_S(v) (((v)==1)?"":"s") using namespace MoleCuilder; QtStatusBar::QtStatusBar(QWidget *_parent) : QStatusBar(_parent), Observer("QtStatusBar"), atomCount(World::getInstance().numAtoms()), moleculeCount(World::getInstance().numMolecules()), parent(_parent), activeProcess(""), StatusList(ActionQueue::getInstance().getStatusList()), StatusList_signedOn(false), timer(NULL), timer_interval(4000) { World::getInstance().signOn(this); Process::AddObserver(this); StatusList.signOn(this, ActionStatusList::StatusAdded); StatusList_signedOn = true; statusLabel = new QLabel(this); statusLabel->setFrameStyle(QFrame::NoFrame | QFrame::Plain); addPermanentWidget(statusLabel); redrawStatus(); // connect the timer timer = new QTimer(this); timer->stop(); connect(timer, SIGNAL(timeout()), this, SLOT(updateStatusMessage())); qRegisterMetaType("std::string"); connect( this, SIGNAL(redrawProgressBar(const std::string, const unsigned int, const unsigned int, const bool)), this, SLOT(updateProgressBar(const std::string, const unsigned int, const unsigned int, const bool))); } QtStatusBar::~QtStatusBar() { // stop the timer if it is running if (timer->isActive()) timer->stop(); Process::RemoveObserver(this); World::getInstance().signOff(this); if (StatusList_signedOn) StatusList.signOff(this, ActionStatusList::StatusAdded); } void QtStatusBar::paintEvent(QPaintEvent * event) { boost::recursive_mutex::scoped_lock lock(refill_mutex); QStatusBar::paintEvent(event); } void QtStatusBar::update(Observable *subject) { if (subject == World::getPointer()){ atomCount = World::getInstance().numAtoms(); moleculeCount = World::getInstance().numMolecules(); // redraw only if no timer updates messages if (!timer->isActive()) redrawStatus(); } else if (subject == &StatusList) { // we do not react to general updates from StatusList } else { // we probably have some process // as notify comes from ActionQueue's thread, we have to use signal/slots // to inform ourselves but within the main() thread to be able to add // the progressbar widget. Process *proc; if((proc=dynamic_cast(subject))){ const bool StopStatus = proc->doesStop(); emit redrawProgressBar(proc->getName(), proc->getMaxSteps(), proc->getCurrStep(), StopStatus); } } } void QtStatusBar::startTimer() { timer->start(timer_interval); } void QtStatusBar::stopTimer() { timer->stop(); } void QtStatusBar::updateStatusMessage() { boost::recursive_mutex::scoped_lock lock(refill_mutex); if (StatusList.size() != 0) { // get oldest message from the StatusList const std::string message = StatusList.popFirstMessage(); statusLabel->setText(QString(message.c_str())); } else { // just send the standard message redrawStatus(); // and stop the timer stopTimer(); } } void QtStatusBar::recieveNotification(Observable *_publisher, Notification *_notification) { if (_publisher == &StatusList) { switch(_notification->getChannelNo()) { case MoleCuilder::ActionStatusList::StatusAdded: if (!timer->isActive()) { // if timer is not already running updateStatusMessage(); startTimer(); } break; } } } void QtStatusBar::subjectKilled(Observable *subject) { // Processes don't notify when they are killed if (subject == &StatusList) { // print all remaining messages while (StatusList.size() != 0) updateStatusMessage(); // don't need to sign off, just note down that we are StatusList_signedOn = false; } else { atomCount = World::getInstance().numAtoms(); moleculeCount = World::getInstance().numMolecules(); World::getInstance().signOn(this); redrawStatus(); } } void QtStatusBar::redrawStatus() { boost::recursive_mutex::scoped_lock lock(refill_mutex); stringstream sstr; sstr << "You have " << atomCount << " atom" << PLURAL_S(atomCount) <<" in " << moleculeCount << " molecule" << PLURAL_S(moleculeCount); statusLabel->setText(QString(sstr.str().c_str())); } void QtStatusBar::updateProgressBar( const std::string name, const unsigned int maxsteps, const unsigned int currentstep, const bool StopStatus) { boost::recursive_mutex::scoped_lock lock(refill_mutex); progressIndicator *ind=0; progressBars_t::iterator iter = progressBars.find(name); // see what we have to do with the process if (iter == progressBars.end()) { ind = new progressIndicator(name); ind->bar->setMaximum(maxsteps); progressBars.insert( std::make_pair(name,ind) ); } else { ind = iter->second; } if (activeProcess != name) { addWidget(ind->container); activeProcess = name; } ind->bar->setValue(currentstep); parent->repaint(); if ((iter != progressBars.end()) && StopStatus) { removeWidget(ind->container); activeProcess = std::string(""); progressBars.erase(name); delete ind; } } QtStatusBar::progressIndicator::progressIndicator(const std::string &name) { stringstream sstr; sstr << "Busy (" << name << ")"; container = new QWidget(); layout = new QHBoxLayout(container); label = new QLabel(QString(sstr.str().c_str())); bar = new QProgressBar(); layout->addWidget(label); layout->addWidget(bar); container->setLayout(layout); } QtStatusBar::progressIndicator::~progressIndicator(){ delete container; }