|
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.
|