Switch to unified view

a/src/qtgui/rclmain_w.cpp b/src/qtgui/rclmain_w.cpp
...
...
46
#include <qpushbutton.h>
46
#include <qpushbutton.h>
47
#include <qimage.h>
47
#include <qimage.h>
48
#include <qapplication.h>
48
#include <qapplication.h>
49
#include <qcursor.h>
49
#include <qcursor.h>
50
#include <qevent.h>
50
#include <qevent.h>
51
#include <QFileSystemWatcher>
51
52
52
#include "recoll.h"
53
#include "recoll.h"
53
#include "debuglog.h"
54
#include "debuglog.h"
54
#include "mimehandler.h"
55
#include "mimehandler.h"
55
#include "pathut.h"
56
#include "pathut.h"
...
...
71
#include "listdialog.h"
72
#include "listdialog.h"
72
#include "firstidx.h"
73
#include "firstidx.h"
73
#include "idxsched.h"
74
#include "idxsched.h"
74
#include "crontool.h"
75
#include "crontool.h"
75
#include "rtitool.h"
76
#include "rtitool.h"
77
#include "indexer.h"
76
78
77
using namespace confgui;
79
using namespace confgui;
78
80
79
#include "rclmain_w.h"
81
#include "rclmain_w.h"
80
#include "rclhelp.h"
82
#include "rclhelp.h"
...
...
95
    };
97
    };
96
    DocSequence::set_translations((const char *)tr("sorted").toUtf8(), 
98
    DocSequence::set_translations((const char *)tr("sorted").toUtf8(), 
97
                (const char *)tr("filtered").toUtf8());
99
                (const char *)tr("filtered").toUtf8());
98
100
99
    periodictimer = new QTimer(this);
101
    periodictimer = new QTimer(this);
100
102
    m_watcher.addPath(QString::fromLocal8Bit(
103
            theconfig->getIdxStatusFile().c_str()));
101
    // At least some versions of qt4 don't display the status bar if
104
    // At least some versions of qt4 don't display the status bar if
102
    // it's not created here.
105
    // it's not created here.
103
    (void)statusBar();
106
    (void)statusBar();
104
107
105
    (void)new HelpClient(this);
108
    (void)new HelpClient(this);
...
...
201
    QKeySequence seq("Ctrl+Shift+s");
204
    QKeySequence seq("Ctrl+Shift+s");
202
    QShortcut *sc = new QShortcut(seq, this);
205
    QShortcut *sc = new QShortcut(seq, this);
203
    connect(sc, SIGNAL (activated()), 
206
    connect(sc, SIGNAL (activated()), 
204
        this, SLOT (focusToSearch()));
207
        this, SLOT (focusToSearch()));
205
208
209
    connect(&m_watcher, SIGNAL(fileChanged(QString)), 
210
      this, SLOT(idxStatus()));
206
    connect(sSearch, SIGNAL(startSearch(RefCntr<Rcl::SearchData>)), 
211
    connect(sSearch, SIGNAL(startSearch(RefCntr<Rcl::SearchData>)), 
207
        this, SLOT(startSearch(RefCntr<Rcl::SearchData>)));
212
        this, SLOT(startSearch(RefCntr<Rcl::SearchData>)));
208
    connect(sSearch, SIGNAL(clearSearch()), 
213
    connect(sSearch, SIGNAL(clearSearch()), 
209
        this, SLOT(resetSearch()));
214
        this, SLOT(resetSearch()));
210
215
...
...
471
    if (asearchform)
476
    if (asearchform)
472
    delete asearchform;
477
    delete asearchform;
473
    // We'd prefer to do this in the exit handler, but it's apparently to late
478
    // We'd prefer to do this in the exit handler, but it's apparently to late
474
    // and some of the qt stuff is already dead at this point?
479
    // and some of the qt stuff is already dead at this point?
475
    LOGDEB2(("RclMain::fileExit() : stopping idx thread\n"));
480
    LOGDEB2(("RclMain::fileExit() : stopping idx thread\n"));
476
    stop_idxthread();
481
482
    // Do we want to stop an ongoing index operation here ? 
483
    // I guess not. We did use to cancel the indexing thread.
484
477
    // Let the exit handler clean up the rest (internal recoll stuff).
485
    // Let the exit handler clean up the rest (internal recoll stuff).
478
    exit(0);
486
    exit(0);
479
}
487
}
480
488
489
void RclMain::idxStatus()
490
{
491
    ConfSimple cs(theconfig->getIdxStatusFile().c_str(), 1);
492
    QString msg = tr("Indexing in progress: ");
493
    DbIxStatus status;
494
    string val;
495
    cs.get("phase", val);
496
    status.phase = DbIxStatus::Phase(atoi(val.c_str()));
497
    cs.get("fn", status.fn);
498
    cs.get("docsdone", val);
499
    status.docsdone = atoi(val.c_str());
500
    cs.get("filesdone", val);
501
    status.filesdone = atoi(val.c_str());
502
    cs.get("dbtotdocs", val);
503
    status.dbtotdocs = atoi(val.c_str());
504
505
    QString phs;
506
    switch (status.phase) {
507
    case DbIxStatus::DBIXS_NONE:phs=tr("None");break;
508
    case DbIxStatus::DBIXS_FILES: phs=tr("Updating");break;
509
    case DbIxStatus::DBIXS_PURGE: phs=tr("Purge");break;
510
    case DbIxStatus::DBIXS_STEMDB: phs=tr("Stemdb");break;
511
    case DbIxStatus::DBIXS_CLOSING:phs=tr("Closing");break;
512
    case DbIxStatus::DBIXS_DONE:phs=tr("Done");break;
513
    case DbIxStatus::DBIXS_MONITOR:phs=tr("Monitor");break;
514
    default: phs=tr("Unknown");break;
515
    }
516
    msg += phs + " ";
517
    if (status.phase == DbIxStatus::DBIXS_FILES) {
518
  char cnts[100];
519
  if (status.dbtotdocs > 0)
520
      sprintf(cnts,"(%d/%d/%d) ", status.docsdone, status.filesdone, 
521
          status.dbtotdocs);
522
  else
523
      sprintf(cnts, "(%d/%d) ", status.docsdone, status.filesdone);
524
  msg += QString::fromAscii(cnts) + " ";
525
    }
526
    string mf;int ecnt = 0;
527
    string fcharset = theconfig->getDefCharset(true);
528
    if (!transcode(status.fn, mf, fcharset, "UTF-8", &ecnt) || ecnt) {
529
  mf = url_encode(status.fn, 0);
530
    }
531
    msg += QString::fromUtf8(mf.c_str());
532
    statusBar()->showMessage(msg, 4000);
533
}
534
481
// This is called by a periodic timer to check the status of the
535
// This is called by a periodic timer to check the status of 
482
// indexing thread and a possible need to exit
536
// indexing, a possible need to exit, and cleanup exited viewers
483
void RclMain::periodic100()
537
void RclMain::periodic100()
484
{
538
{
485
    // Check if indexing thread done
539
    LOGDEB2(("Periodic100\n"));
486
    if (idxthread_getStatus() != IDXTS_NULL) {
540
    if (m_idxproc) {
487
  // Indexing is stopped
541
  // An indexing process was launched. If its' done, see status.
488
  fileToggleIndexingAction->setText(tr("Update &Index"));
542
  int status;
489
  fileToggleIndexingAction->setEnabled(TRUE);
543
  bool exited = m_idxproc->maybereap(&status);
490
  if (m_idxStatusAck == false) {
544
  if (exited) {
491
      m_idxStatusAck = true;
545
      deleteZ(m_idxproc);
492
      if (idxthread_getStatus() != IDXTS_OK) {
546
      if (status) {
493
      if (idxthread_idxInterrupted()) {
494
            QMessageBox::warning(0, "Recoll", 
547
        QMessageBox::warning(0, "Recoll", 
495
                   tr("Indexing interrupted"));
548
                     tr("Indexing failed"));
496
      } else {
497
          QMessageBox::warning(0, "Recoll", 
498
             QString::fromAscii(idxthread_getReason().c_str()));
499
      }
500
        }
549
        }
501
      // Make sure we reopen the db to get the results. If there
502
      // is current search data, we should reset it else things
503
      // are inconsistent (ie: applying sort will fail. But we
504
      // don't like erasing results while the user may be
505
      // looking at them either). Fixing this would be
506
      // relatively complicated (keep an open/close gen number
507
      // and check this / restart query in DocSeqDb() ?)
508
        string reason;
550
        string reason;
509
        maybeOpenDb(reason, 1);
551
        maybeOpenDb(reason, 1);
510
            periodictimer->setInterval(1000);
552
  } else {
553
      // update/show status even if the status file did not
554
      // change (else the status line goes blank during
555
      // lengthy operations).
556
      idxStatus();
511
    }
557
    }
512
    } else {
558
    }
513
  // Indexing is running
559
    // Update the "start/stop indexing" menu entry, can't be done from
514
  m_idxStatusAck = false;
560
    // the "start/stop indexing" slot itself
561
    if (m_idxproc) {
515
    fileToggleIndexingAction->setText(tr("Stop &Indexing"));
562
    fileToggleIndexingAction->setText(tr("Stop &Indexing"));
516
    fileToggleIndexingAction->setEnabled(TRUE);
563
    fileToggleIndexingAction->setEnabled(TRUE);
517
        periodictimer->setInterval(100);
564
    } else {
518
  // The toggle thing is for the status to flash
565
  fileToggleIndexingAction->setText(tr("Update &Index"));
519
  if (m_periodicToggle < 9) {
566
  // No indexer of our own runnin, but the real time one may be up, check
520
      QString msg = tr("Indexing in progress: ");
567
  // for some other indexer.
521
      DbIxStatus status = idxthread_idxStatus();
568
  Pidfile pidfile(theconfig->getPidfile());
522
      QString phs;
569
  if (pidfile.open() == 0) {
523
      switch (status.phase) {
570
      fileToggleIndexingAction->setEnabled(TRUE);
524
      case DbIxStatus::DBIXS_FILES: phs=tr("Files");break;
571
  } else {
525
      case DbIxStatus::DBIXS_PURGE: phs=tr("Purge");break;
572
      fileToggleIndexingAction->setEnabled(FALSE);
526
      case DbIxStatus::DBIXS_STEMDB: phs=tr("Stemdb");break;
573
  }       
527
      case DbIxStatus::DBIXS_CLOSING:phs=tr("Closing");break;
528
      default: phs=tr("Unknown");break;
529
      }
574
    }
530
      msg += phs + " ";
575
531
      if (status.phase == DbIxStatus::DBIXS_FILES) {
576
    // Possibly cleanup the dead viewers
532
      char cnts[100];
577
    for (vector<ExecCmd*>::iterator it = m_viewers.begin();
533
      if (status.dbtotdocs>0)
578
   it != m_viewers.end(); it++) {
534
          sprintf(cnts,"(%d/%d) ",status.docsdone, status.dbtotdocs);
579
  int status;
535
      else
580
  if ((*it)->maybereap(&status)) {
536
          sprintf(cnts, "(%d) ", status.docsdone);
581
      deleteZ(*it);
537
      msg += QString::fromAscii(cnts) + " ";
538
      }
539
      string mf;int ecnt = 0;
540
      string fcharset = theconfig->getDefCharset(true);
541
      if (!transcode(status.fn, mf, fcharset, "UTF-8", &ecnt) || ecnt) {
542
      mf = url_encode(status.fn, 0);
543
      }
544
      msg += QString::fromUtf8(mf.c_str());
545
      statusBar()->showMessage(msg, 4000);
546
  } else if (m_periodicToggle == 9) {
547
      statusBar()->showMessage("");
548
    }
582
    }
549
  if (++m_periodicToggle >= 10)
550
      m_periodicToggle = 0;
551
    }
583
    }
584
    vector<ExecCmd*> v;
585
    for (vector<ExecCmd*>::iterator it = m_viewers.begin();
586
   it != m_viewers.end(); it++) {
587
  if (*it)
588
      v.push_back(*it);
589
    }
590
    m_viewers = v;
591
552
    if (recollNeedsExit)
592
    if (recollNeedsExit)
553
    fileExit();
593
    fileExit();
554
}
594
}
555
595
556
// This gets called when the indexing action is activated. It starts
596
// This gets called when the indexing action is activated. It starts
557
// the requested action, and disables the menu entry. This will be
597
// the requested action, and disables the menu entry. This will be
558
// re-enabled by the indexing status check
598
// re-enabled by the indexing status check
559
void RclMain::toggleIndexing()
599
void RclMain::toggleIndexing()
560
{
600
{
561
    if (idxthread_getStatus() == IDXTS_NULL) {
601
    if (m_idxproc) {
562
  // Indexing was in progress, stop it
602
  // Indexing was in progress, request stop. Let the periodic
563
  stop_indexing();
603
  // routine check for the results.
564
        periodictimer->setInterval(1000);
604
  kill(m_idxproc->getChildPid(), SIGTERM);
565
  fileToggleIndexingAction->setText(tr("Update &Index"));
566
    } else {
605
    } else {
567
  start_indexing(false);
606
  list<string> args;
568
        periodictimer->setInterval(100);
607
  args.push_back("-c");
608
  args.push_back(theconfig->getConfDir());
609
  m_idxproc = new ExecCmd;
610
  m_idxproc->startExec("recollindex", args, false, false);
569
    fileToggleIndexingAction->setText(tr("Stop &Indexing"));
611
    fileToggleIndexingAction->setText(tr("Stop &Indexing"));
570
    }
612
    }
571
    fileToggleIndexingAction->setEnabled(FALSE);
613
    fileToggleIndexingAction->setEnabled(FALSE);
572
}
614
}
573
615
574
// Start a db query and set the reslist docsource
616
// Start a db query and set the reslist docsource
575
void RclMain::startSearch(RefCntr<Rcl::SearchData> sdata)
617
void RclMain::startSearch(RefCntr<Rcl::SearchData> sdata)
576
{
618
{
577
    LOGDEB(("RclMain::startSearch. Indexing %s\n", 
619
    LOGDEB(("RclMain::startSearch. Indexing %s\n", m_idxproc?"on":"off"));
578
      idxthread_getStatus() == IDXTS_NULL?"on":"off"));
579
    emit searchReset();
620
    emit searchReset();
580
    m_source = RefCntr<DocSequence>();
621
    m_source = RefCntr<DocSequence>();
581
622
582
    // The db may have been closed at the end of indexing
623
    // The db may have been closed at the end of indexing
583
    string reason;
624
    string reason;
584
    // If indexing is being performed, we reopen the db at each query.
625
    // If indexing is being performed, we reopen the db at each query.
585
    if (!maybeOpenDb(reason, idxthread_getStatus() == IDXTS_NULL)) {
626
    if (!maybeOpenDb(reason, m_idxproc != 0)) {
586
    QMessageBox::critical(0, "Recoll", QString(reason.c_str()));
627
    QMessageBox::critical(0, "Recoll", QString(reason.c_str()));
587
    return;
628
    return;
588
    }
629
    }
589
630
590
    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
631
    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
...
...
968
        if (rcldb->needUpdate(udi, sig)) {
1009
        if (rcldb->needUpdate(udi, sig)) {
969
        int rep = 
1010
        int rep = 
970
            QMessageBox::warning(0, tr("Warning"), 
1011
            QMessageBox::warning(0, tr("Warning"), 
971
                       tr("Index not up to date for this file. "
1012
                       tr("Index not up to date for this file. "
972
                    "Refusing to risk showing the wrong "
1013
                    "Refusing to risk showing the wrong "
973
                    "data. Click ok to update the "
1014
                    "entry. Click Ok to update the "
974
                    "index for this file, then re-run the "
1015
                    "index for this file, then re-run the "
975
                    "query when indexing is done. "
1016
                    "query when indexing is done. "
976
                    "Else, Cancel."),
1017
                    "Else, Cancel."),
977
                     QMessageBox::Ok,
1018
                     QMessageBox::Ok,
978
                     QMessageBox::Cancel,
1019
                     QMessageBox::Cancel,
979
                     QMessageBox::NoButton);
1020
                     QMessageBox::NoButton);
980
        if (rep == QMessageBox::Ok) {
1021
        if (rep == QMessageBox::Ok) {
981
            LOGDEB(("Requesting index update for %s\n", 
1022
            LOGDEB(("Requesting index update for %s\n", 
982
                doc.url.c_str()));
1023
                doc.url.c_str()));
983
          start_indexing(false, vector<Rcl::Doc>(1, doc));
1024
          vector<Rcl::Doc> docs(1, doc);
1025
          updateIdxForDocs(docs);
984
        }
1026
        }
985
        return;
1027
        return;
986
        }
1028
        }
987
    }
1029
    }
988
    }
1030
    }
...
...
1021
    curPreview->show();
1063
    curPreview->show();
1022
    } 
1064
    } 
1023
    curPreview->makeDocCurrent(doc, docnum);
1065
    curPreview->makeDocCurrent(doc, docnum);
1024
}
1066
}
1025
1067
1068
void RclMain::updateIdxForDocs(vector<Rcl::Doc>& docs)
1069
{
1070
    if (m_idxproc) {
1071
  QMessageBox::warning(0, tr("Warning"), 
1072
               tr("Can't update index: indexer running"),
1073
               QMessageBox::Ok, 
1074
               QMessageBox::NoButton);
1075
  return;
1076
    }
1077
  
1078
    vector<string> paths;
1079
    if (ConfIndexer::docsToPaths(docs, paths)) {
1080
  list<string> args;
1081
  args.push_back("-c");
1082
  args.push_back(theconfig->getConfDir());
1083
  args.push_back("-i");
1084
  args.insert(args.end(), paths.begin(), paths.end());
1085
  m_idxproc = new ExecCmd;
1086
  m_idxproc->startExec("recollindex", args, false, false);
1087
  fileToggleIndexingAction->setText(tr("Stop &Indexing"));
1088
    }
1089
    fileToggleIndexingAction->setEnabled(FALSE);
1090
}
1091
1026
/** 
1092
/** 
1027
 * Open a preview window for a given document, no linking to result list
1093
 * Open a preview window for a given document, no linking to result list
1028
 *
1094
 *
1029
 * This is used to show ie parent documents, which have no corresponding
1095
 * This is used to show ie parent documents, which have no corresponding
1030
 * entry in the result list.
1096
 * entry in the result list.