"Fossies" - the Fresh Open Source Software Archive

Member "MP3Diags-unstable-1.5.01/src/ThreadRunnerDlgImpl.cpp" (10 Feb 2019, 10280 Bytes) of package /linux/privat/MP3Diags-unstable-1.5.01.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ThreadRunnerDlgImpl.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.3.04_vs_1.5.01.

    1 /***************************************************************************
    2  *   MP3 Diags - diagnosis, repairs and tag editing for MP3 files          *
    3  *                                                                         *
    4  *   Copyright (C) 2009 by Marian Ciobanu                                  *
    5  *   ciobi@inbox.com                                                       *
    6  *                                                                         *
    7  *   This program is free software; you can redistribute it and/or modify  *
    8  *   it under the terms of the GNU General Public License version 2 as     *
    9  *   published by the Free Software Foundation.                            *
   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  *   You should have received a copy of the GNU General Public License     *
   17  *   along with this program; if not, write to the                         *
   18  *   Free Software Foundation, Inc.,                                       *
   19  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
   20  ***************************************************************************/
   21 
   22 
   23 #include  <QCloseEvent>
   24 #include  <QLocale>
   25 #include <QAction>
   26 
   27 #include  <ctime>
   28 
   29 #include  "ThreadRunnerDlgImpl.h"
   30 
   31 #include  "Helpers.h"
   32 
   33 
   34 PausableThread::PausableThread(/*QObject* pParent = 0*/) : /*QThread(pParent),*/ m_bPaused(false), m_bAborted(false)
   35 {
   36     static bool s_bRegistered (false);
   37     if (!s_bRegistered)
   38     {
   39         s_bRegistered = true;
   40         qRegisterMetaType<StrList>("StrList");
   41     }
   42 }
   43 
   44 
   45 /*virtual*/ PausableThread::~PausableThread()
   46 {
   47 //qDebug("thread destroyed");
   48 }
   49 
   50 void PausableThread::pause()
   51 {
   52     m_bPaused = true; // !!! no synch needed
   53 }
   54 
   55 
   56 void PausableThread::resume()
   57 {
   58     QMutexLocker lck(&m_mutex);
   59     m_bPaused = false;
   60     m_waitCondition.wakeAll();
   61 }
   62 
   63 
   64 void PausableThread::abort()
   65 {
   66     QMutexLocker lck(&m_mutex);
   67     m_bAborted = true;
   68     m_waitCondition.wakeAll();
   69 }
   70 
   71 
   72 void PausableThread::checkPause() // if m_bPaused is set, it waits until resume() or abort() get called; otherwise it returns immediately
   73 {
   74     if (!m_bPaused) { return; }
   75 
   76     QMutexLocker lck(&m_mutex);
   77     if (!m_bPaused) { return; } // !!! it was tested 2 lines above, but might have changed after that; now it's a different story, because it's protected by the mutex;
   78     if (m_bAborted) { return; }
   79 
   80     m_waitCondition.wait(&m_mutex);
   81 }
   82 
   83 
   84 //=====================================================================================================================
   85 //=====================================================================================================================
   86 //=====================================================================================================================
   87 
   88 
   89 
   90 
   91 ThreadRunnerDlgImpl::ThreadRunnerDlgImpl(QWidget* pParent, Qt::WindowFlags flags, PausableThread* pThread, bool bShowCounter, TruncatePos eTruncatePos, bool bShowPauseAbort /* = true*/) :
   92     QDialog(pParent, flags),
   93     Ui::ThreadRunnerDlg(),
   94 
   95     m_pThread(pThread),
   96     m_nCounter(0),
   97     m_bShowCounter(bShowCounter),
   98     //m_nLastKey(0),
   99 
  100     m_tRealBegin(time(0)),
  101     m_tRunningBegin(time(0)),
  102     m_bShowPauseAbort(bShowPauseAbort),
  103     m_bFirstTime(true),
  104     m_eTruncatePos(eTruncatePos)
  105 {
  106     setupUi(this);
  107 
  108     if (!bShowPauseAbort)
  109     {
  110         m_pPauseResumeB->hide();
  111         m_pAbortB->hide();
  112     }
  113 
  114     pThread->setParent(this);
  115 
  116     connect(m_pThread, SIGNAL(stepChanged(const StrList&, int)), this, SLOT(onStepChanged(const StrList&, int)));
  117     connect(m_pThread, SIGNAL(completed(bool)), this, SLOT(onThreadCompleted(bool)));
  118     connect(&m_closeTimer, SIGNAL(timeout()), this, SLOT(onCloseTimer()));
  119     connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(onUpdateTimer()));
  120 
  121     { QAction* p (new QAction(this)); p->setShortcut(QKeySequence(Qt::Key_Escape)); connect(p, SIGNAL(triggered()), this, SLOT(on_m_pAbortB_clicked())); addAction(p); } // !!! make ESC call on_m_pAbortB_clicked() instead of closing the dialog
  122 
  123     m_pCurrentL->setText("");
  124 
  125     pThread->start();
  126     m_updateTimer.start(500); // 0.5 sec
  127 
  128     { QAction* p (new QAction(this)); p->setShortcut(QKeySequence("F1")); connect(p, SIGNAL(triggered()), this, SLOT(onHelp())); addAction(p); }
  129 }
  130 
  131 ThreadRunnerDlgImpl::~ThreadRunnerDlgImpl()
  132 {
  133 }
  134 
  135 
  136 
  137 void ThreadRunnerDlgImpl::onThreadCompleted(bool bSuccess)
  138 {
  139     m_bSuccess = bSuccess;
  140 
  141     // !!! can't just exit; should wait for the thread's "run()" metod to finish
  142     m_pCurrentL->setText(tr("Completed"));
  143     m_pPauseResumeB->setEnabled(false);
  144     m_pAbortB->setEnabled(false);
  145     m_closeTimer.start(100); // 0.1 sec
  146     onCloseTimer(); // this may return immediately or not, depending on which thread gets executed after "PausableThread::notifComplete()"
  147 }
  148 
  149 
  150 void ThreadRunnerDlgImpl::on_m_pPauseResumeB_clicked()
  151 {
  152     if (!m_pThread->m_bPaused)
  153     { // currently running
  154         m_pPauseResumeB->setText(tr("&Resume"));
  155         m_pThread->pause();
  156 
  157         m_tPauseBegin = time(0);
  158     }
  159     else
  160     { // currently paused
  161         m_pPauseResumeB->setText(tr("&Pause"));
  162 
  163         time_t t (time(0));
  164         m_tRunningBegin = m_tRunningBegin + t - m_tPauseBegin;
  165         m_pThread->resume();
  166     }
  167 }
  168 
  169 
  170 void ThreadRunnerDlgImpl::on_m_pAbortB_clicked()
  171 {
  172     m_pPauseResumeB->setEnabled(false);
  173     m_pAbortB->setEnabled(false);
  174     m_pThread->abort();
  175 }
  176 
  177 
  178 QString ThreadRunnerDlgImpl::truncateLarge(const QString& s, int nKeepFirst /* = 0*/) // truncates strings that are too wide to display without resizing
  179 {
  180     QFontMetrics fontMetrics (m_pCurrentL->font());
  181     const int MARGIN (8); // normally this should be 0 but in other cases Qt missed a few pixels when estimating how much space it needed, so it seems better to lose some pixels // ttt2 2009.04.30 - actually this is probably related to spacing; if this is true, the hard-coded value should be replaced by some query to QApplication::style()->pixelMetric()
  182 
  183     if (fontMetrics.width(s) < m_pCurrentL->width() - MARGIN)
  184     {
  185         return s;
  186     }
  187 
  188     int nSize (s.size() - 1);
  189     QString res (s);
  190 
  191     switch (m_eTruncatePos)
  192     {
  193     case TRUNCATE_BEGIN:
  194         {
  195             res.insert (nKeepFirst, "... ");
  196             nKeepFirst += 4; // size of "... "
  197             nSize -= nKeepFirst;
  198             while (nSize > 0 && fontMetrics.width(res) >= m_pCurrentL->width() - MARGIN)
  199             {
  200                 res.remove(nKeepFirst, 1);
  201                 --nSize;
  202             }
  203             return res;
  204         }
  205 
  206     case TRUNCATE_END:
  207         {
  208             while (nSize > 0 && fontMetrics.width(res + " ...") >= m_pCurrentL->width() - MARGIN)
  209             {
  210                 res.truncate(nSize);
  211                 --nSize;
  212             }
  213             return res + " ...";
  214         }
  215 
  216     default:
  217         //CB_ASSERT (false); //ttt2 add support for TRUNCATE_MIDDLE
  218         CB_THROW(CbRuntimeError);
  219     }
  220 }
  221 
  222 
  223 //void ThreadRunnerDlgImpl::onStepChanged(const QString& qstrLabel1, const QString& qstrLabel2 /* = ""*/, const QString& qstrLabel3 /* = ""*/, const QString& qstrLabel4 /* = ""*/)
  224 void ThreadRunnerDlgImpl::onStepChanged(const StrList& v, int nStep)
  225 {
  226 //qDebug("step %s", qstrLabel.toStdString().c_str());
  227     if (-1 == nStep)
  228     {
  229         ++m_nCounter;
  230     }
  231     else
  232     {
  233         m_nCounter = nStep;
  234     }
  235 
  236     m_vStepInfo = v;
  237     if (m_bFirstTime)
  238     {
  239         QTimer::singleShot(1, this, SLOT(onUpdateTimer()));
  240         m_bFirstTime = false;
  241     }
  242 }
  243 
  244 
  245 static QString getTimeFmt(int n) // n in seconds
  246 {
  247     int h (n / 3600); n -= h*3600;
  248     int m (n / 60); n -= m*60;
  249     QString q;
  250     q.sprintf("%d:%02d:%02d", h, m, n);
  251     return q;
  252 }
  253 
  254 
  255 void ThreadRunnerDlgImpl::onCloseTimer()
  256 {
  257 //qDebug("ThreadRunnerDlgImpl::onTimer()");
  258     if (!m_pThread->isFinished())
  259     {
  260 //qDebug("waithing for thread");
  261         return;
  262     }
  263 
  264     m_closeTimer.stop();
  265     m_updateTimer.stop();
  266 
  267     if (m_bSuccess)
  268     {
  269         accept();
  270     }
  271     else
  272     {
  273         reject();
  274     }
  275 }
  276 
  277 void ThreadRunnerDlgImpl::onUpdateTimer()
  278 {
  279     QString s;
  280     if (m_bShowCounter)
  281     {
  282         static QLocale loc ("C");
  283         s = loc.toString(m_nCounter) + ". ";
  284     }
  285 
  286     int n ((int)m_vStepInfo.size());
  287     if (n >= 1)
  288     {
  289         s = truncateLarge(s + m_vStepInfo[0], s.size());
  290 
  291         for (int i = 1; i < n; ++i)
  292         {
  293             s += "\n" + truncateLarge(m_vStepInfo[i]);
  294         }
  295     }
  296 
  297     time_t t (time(0));
  298     if (m_bShowPauseAbort)
  299     {
  300         s += tr("\n\nTotal time: %1" // ttt1 show Total time only if different from Running time
  301             "\nRunning time: %2").arg(getTimeFmt(t - m_tRealBegin)).arg(getTimeFmt((m_pThread->m_bPaused ? m_tPauseBegin : t) - m_tRunningBegin));
  302     }
  303     else
  304     {
  305         s += "\n\n" + tr("Time: %1").arg(getTimeFmt(t - m_tRealBegin));
  306     }
  307 
  308     m_pCurrentL->setText(s);
  309 }
  310 
  311 
  312 /*override*/ void ThreadRunnerDlgImpl::closeEvent(QCloseEvent* pEvent)
  313 {
  314     pEvent->ignore();
  315     on_m_pAbortB_clicked();
  316 }
  317 
  318 
  319 void ThreadRunnerDlgImpl::onHelp()
  320 {
  321     // openHelp("index.html"); //ttt2 see if anything more specific can be done
  322 }
  323 
  324 
  325 
  326 #if 0
  327 
  328 /*
  329 Not sure if this should work: from the doc for QDialog:
  330 
  331 Escape Key
  332 If the user presses the Esc key in a dialog, QDialog::reject() will be called. This will cause the window to close: The close event cannot be ignored.
  333 
  334 ttt2 see Qt::Key_Escape in MainFormDlgImpl for a different approach, decide which is better
  335 */
  336 
  337 /*override*/ void ThreadRunnerDlgImpl::keyPressEvent(QKeyEvent* pEvent)
  338 {
  339 //qDebug("key prs %d", pEvent->key());
  340 
  341     m_nLastKey = pEvent->key();
  342 
  343     pEvent->ignore();
  344 }
  345 
  346 
  347 /*override*/ void ThreadRunnerDlgImpl::keyReleaseEvent(QKeyEvent* pEvent)
  348 {
  349 //qDebug("key rel %d", pEvent->key());
  350     if (Qt::Key_Escape == pEvent->key())
  351     {
  352         on_m_pAbortB_clicked();
  353     }
  354     pEvent->ignore(); // ttt2 not sure this is the way to do it, but the point is to disable the ESC key
  355 }
  356 
  357 #endif