Switch to unified view

a/src/qtgui/restable.cpp b/src/qtgui/restable.cpp
...
...
28
#include <QMenu>
28
#include <QMenu>
29
#include <QScrollBar>
29
#include <QScrollBar>
30
#include <QStyledItemDelegate>
30
#include <QStyledItemDelegate>
31
#include <QTextDocument>
31
#include <QTextDocument>
32
#include <QPainter>
32
#include <QPainter>
33
#include <QSplitter>
34
#include <QClipboard>
33
35
34
#include "recoll.h"
36
#include "recoll.h"
35
#include "refcntr.h"
37
#include "refcntr.h"
36
#include "docseq.h"
38
#include "docseq.h"
37
#include "debuglog.h"
39
#include "debuglog.h"
...
...
45
// Compensate for the default and somewhat bizarre vertical placement
47
// Compensate for the default and somewhat bizarre vertical placement
46
// of text in cells
48
// of text in cells
47
static const int ROWHEIGHTPAD = 2;
49
static const int ROWHEIGHTPAD = 2;
48
static const int TEXTINCELLVTRANS = -4;
50
static const int TEXTINCELLVTRANS = -4;
49
51
50
//////////////////////////////////
52
//////////////////////////////////////////////////////////////////////////////
53
// Restable hiliter: to highlight search term in the table. This is actually
54
// the same as reslist's, could be shared.
55
class PlainToRichQtReslist : public PlainToRich {
56
public:
57
    virtual ~PlainToRichQtReslist() {}
58
    virtual string startMatch() {
59
  return string("<span style='color: ")
60
      + string((const char *)prefs.qtermcolor.toAscii()) + string("'>");
61
    }
62
    virtual string endMatch() {return string("</span>");}
63
};
64
static PlainToRichQtReslist g_hiliter;
65
66
//////////////////////////////////////////////////////////////////////////
51
// Restable "pager". We use it to display a single doc details in the 
67
// Restable "pager". We use it to print details for a document in the 
52
// detail area
68
// detail area
53
///
69
///
54
class ResTablePager : public ResListPager {
70
class ResTablePager : public ResListPager {
55
public:
71
public:
56
    ResTablePager(ResTable *p)
72
    ResTablePager(ResTable *p)
...
...
62
    virtual string iconPath(const string& mt);
78
    virtual string iconPath(const string& mt);
63
private:
79
private:
64
    ResTable *m_parent;
80
    ResTable *m_parent;
65
};
81
};
66
82
67
//////////////////////////
68
// Restable hiliter: to highlight search term in the table. This is actually
69
// the same as reslist's, could be shared.
70
class PlainToRichQtReslist : public PlainToRich {
71
public:
72
    virtual ~PlainToRichQtReslist() {}
73
    virtual string startMatch() {
74
  return string("<span style='color: ")
75
      + string((const char *)prefs.qtermcolor.toAscii()) + string("'>");
76
    }
77
    virtual string endMatch() {return string("</span>");}
78
};
79
static PlainToRichQtReslist g_hiliter;
80
/////////////////////////////////////
81
82
bool ResTablePager::append(const string& data, int docnum, const Rcl::Doc&)
83
bool ResTablePager::append(const string& data, int, const Rcl::Doc&)
83
{
84
{
84
    m_parent->textBrowser->moveCursor(QTextCursor::End, 
85
    m_parent->m_detail->moveCursor(QTextCursor::End, 
85
                      QTextCursor::MoveAnchor);
86
                      QTextCursor::MoveAnchor);
86
    m_parent->textBrowser->textCursor().insertBlock();
87
    m_parent->m_detail->textCursor().insertBlock();
87
    m_parent->textBrowser->insertHtml(QString::fromUtf8(data.c_str()));
88
    m_parent->m_detail->insertHtml(QString::fromUtf8(data.c_str()));
88
    m_parent->m_detaildocnum = docnum;
89
    return true;
89
    return true;
90
}
90
}
91
91
92
string ResTablePager::trans(const string& in)
92
string ResTablePager::trans(const string& in)
93
{
93
{
...
...
104
    string iconpath;
104
    string iconpath;
105
    rclconfig->getMimeIconName(mtype, &iconpath);
105
    rclconfig->getMimeIconName(mtype, &iconpath);
106
    return iconpath;
106
    return iconpath;
107
}
107
}
108
108
109
//////////////////////////////////////////////
109
/////////////////////////////////////////////////////////////////////////////
110
/// Detail text area methods
111
112
ResTableDetailArea::ResTableDetailArea(ResTable* parent)
113
    : QTextBrowser(parent), m_table(parent)
114
{
115
    setContextMenuPolicy(Qt::CustomContextMenu);
116
    connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),
117
      this, SLOT(createPopupMenu(const QPoint&)));
118
}
119
120
void ResTableDetailArea::createPopupMenu(const QPoint& pos)
121
{
122
    if (!m_table || m_table->m_detaildocnum < 0) {
123
  LOGDEB(("ResTableDetailArea::createPopupMenu: no table/detaildoc\n"));
124
  return;
125
    }
126
    QMenu *popup = new QMenu(this);
127
    popup->addAction(tr("&Preview"), m_table, SLOT(menuPreview()));
128
    popup->addAction(tr("&Open"), m_table, SLOT(menuEdit()));
129
    popup->addAction(tr("Copy &File Name"), m_table, SLOT(menuCopyFN()));
130
    popup->addAction(tr("Copy &URL"), m_table, SLOT(menuCopyURL()));
131
    if (!m_table->m_detaildoc.ipath.empty())
132
  popup->addAction(tr("&Write to File"), m_table, SLOT(menuSaveToFile()));
133
    popup->addAction(tr("Find &similar documents"), m_table, SLOT(menuExpand()));
134
    popup->addAction(tr("Preview P&arent document/folder"), 
135
            m_table, SLOT(menuPreviewParent()));
136
    popup->addAction(tr("&Open Parent document/folder"), 
137
            m_table, SLOT(menuOpenParent()));
138
    popup->popup(mapToGlobal(pos));
139
}
140
141
//////////////////////////////////////////////////////////////////////////////
110
//// Data model methods
142
//// Data model methods
111
////
143
////
112
144
113
// Routines used to extract named data from an Rcl::Doc. The basic one just uses the meta map. Others
145
// Routines used to extract named data from an Rcl::Doc. The basic one just uses the meta map. Others
114
// (ie: the date ones) need to do a little processing
146
// (ie: the date ones) need to do a little processing
...
...
401
    tableView->setModel(m_model);
433
    tableView->setModel(m_model);
402
    tableView->setMouseTracking(true);
434
    tableView->setMouseTracking(true);
403
    tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
435
    tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
404
    tableView->setSelectionMode(QAbstractItemView::SingleSelection);
436
    tableView->setSelectionMode(QAbstractItemView::SingleSelection);
405
    tableView->setItemDelegate(new ResTableDelegate(this));
437
    tableView->setItemDelegate(new ResTableDelegate(this));
438
    tableView->setContextMenuPolicy(Qt::CustomContextMenu);
439
    connect(tableView, SIGNAL(customContextMenuRequested(const QPoint&)),
440
      this, SLOT(createPopupMenu(const QPoint&)));
406
441
407
    QHeaderView *header = tableView->horizontalHeader();
442
    QHeaderView *header = tableView->horizontalHeader();
408
    if (header) {
443
    if (header) {
409
    if (int(prefs.restableColWidths.size()) == header->count()) {
444
    if (int(prefs.restableColWidths.size()) == header->count()) {
410
        for (int i = 0; i < header->count(); i++) {
445
        for (int i = 0; i < header->count(); i++) {
...
...
444
    QList<int> sizes;
479
    QList<int> sizes;
445
    sizes << 355 << 125;
480
    sizes << 355 << 125;
446
    splitter->setSizes(sizes);
481
    splitter->setSizes(sizes);
447
    }
482
    }
448
483
484
    delete textBrowser;
485
    m_detail = new ResTableDetailArea(this);
449
    textBrowser->setReadOnly(TRUE);
486
    m_detail->setReadOnly(TRUE);
450
    textBrowser->setUndoRedoEnabled(FALSE);
487
    m_detail->setUndoRedoEnabled(FALSE);
451
    textBrowser->setOpenLinks(FALSE);
488
    m_detail->setOpenLinks(FALSE);
452
    // signals and slots connections
489
    // signals and slots connections
453
    connect(textBrowser, SIGNAL(anchorClicked(const QUrl &)), 
490
    connect(m_detail, SIGNAL(anchorClicked(const QUrl &)), 
454
        this, SLOT(linkWasClicked(const QUrl &)));
491
        this, SLOT(linkWasClicked(const QUrl &)));
455
492
    splitter->addWidget(m_detail);
493
    splitter->setOrientation(Qt::Vertical);
456
}
494
}
457
495
458
// This is called by rclmain_w prior to exiting
496
// This is called by rclmain_w prior to exiting
459
void ResTable::saveColState()
497
void ResTable::saveColState()
460
{
498
{
...
...
492
530
493
    if (!m_model || m_model->getDocSource().isNull())
531
    if (!m_model || m_model->getDocSource().isNull())
494
    return;
532
    return;
495
    Rcl::Doc doc;
533
    Rcl::Doc doc;
496
    if (m_model->getDocSource()->getDoc(index.row(), doc)) {
534
    if (m_model->getDocSource()->getDoc(index.row(), doc)) {
497
  textBrowser->clear();
535
  m_detail->clear();
498
    m_detaildocnum = index.row();
536
    m_detaildocnum = index.row();
537
  m_detaildoc = doc;
499
    m_pager->displayDoc(rclconfig, index.row(), doc, m_model->m_hdata);
538
    m_pager->displayDoc(rclconfig, index.row(), doc, m_model->m_hdata);
539
    } else {
540
  m_detaildocnum = -1;
500
    }
541
    }
501
}
542
}
502
543
503
void ResTable::on_tableView_entered(const QModelIndex& index)
544
void ResTable::on_tableView_entered(const QModelIndex& index)
504
{
545
{
...
...
513
    LOGDEB(("ResTable::setDocSource\n"));
554
    LOGDEB(("ResTable::setDocSource\n"));
514
    if (m_model)
555
    if (m_model)
515
    m_model->setDocSource(nsource);
556
    m_model->setDocSource(nsource);
516
    if (m_pager)
557
    if (m_pager)
517
    m_pager->setDocSource(nsource, 0);
558
    m_pager->setDocSource(nsource, 0);
518
    if (textBrowser)
559
    if (m_detail)
519
  textBrowser->clear();
560
  m_detail->clear();
561
    m_detaildocnum = -1;
520
}
562
}
521
563
522
void ResTable::resetSource()
564
void ResTable::resetSource()
523
{
565
{
524
    LOGDEB(("ResTable::resetSource\n"));
566
    LOGDEB(("ResTable::resetSource\n"));
...
...
567
    LOGDEB(("ResTable::readDocSource(%d)\n", int(resetPos)));
609
    LOGDEB(("ResTable::readDocSource(%d)\n", int(resetPos)));
568
    if (resetPos)
610
    if (resetPos)
569
    tableView->verticalScrollBar()->setSliderPosition(0);
611
    tableView->verticalScrollBar()->setSliderPosition(0);
570
612
571
    m_model->readDocSource();
613
    m_model->readDocSource();
572
    textBrowser->clear();
614
    m_detail->clear();
615
    m_detaildocnum = -1;
573
}
616
}
574
617
575
void ResTable::linkWasClicked(const QUrl &url)
618
void ResTable::linkWasClicked(const QUrl &url)
576
{
619
{
577
    if (!m_model || m_model->getDocSource().isNull())
620
    if (m_detaildocnum < 0) {
578
    return;
621
    return;
622
    }
579
    QString s = url.toString();
623
    QString s = url.toString();
580
    const char *ascurl = s.toAscii();
624
    const char *ascurl = s.toAscii();
581
    LOGDEB(("ResTable::linkWasClicked: [%s]\n", ascurl));
625
    LOGDEB(("ResTable::linkWasClicked: [%s]\n", ascurl));
582
626
583
    int i = atoi(ascurl+1) -1;
627
    int i = atoi(ascurl+1) -1;
584
    int what = ascurl[0];
628
    int what = ascurl[0];
585
    switch (what) {
629
    switch (what) {
586
    case 'P': 
630
    case 'P': 
587
    case 'E': 
631
    case 'E': 
588
    {
632
    {
589
  Rcl::Doc doc;
590
  if (!m_model->getDocSource()->getDoc(i, doc)) {
591
      LOGERR(("ResTable::linkWasClicked: can't get doc for %d\n", i));
592
      return;
593
  }
594
    if (what == 'P')
633
    if (what == 'P')
595
        emit docPreviewClicked(i, doc, 0);
634
        emit docPreviewClicked(i, m_detaildoc, 0);
596
    else
635
    else
597
        emit docEditClicked(doc);
636
        emit docEditClicked(m_detaildoc);
598
    }
637
    }
599
    break;
638
    break;
600
    default: 
639
    default: 
601
    LOGERR(("ResList::linkWasClicked: bad link [%s]\n", ascurl));
640
    LOGERR(("ResTable::linkWasClicked: bad link [%s]\n", ascurl));
602
    break;// ?? 
641
    break;// ?? 
603
    }
642
    }
643
}
644
645
void ResTable::createPopupMenu(const QPoint& pos)
646
{
647
    LOGDEB(("ResTable::createPopupMenu: m_detaildocnum %d\n", m_detaildocnum));
648
    if (m_detaildocnum < 0)
649
  return;
650
    QMenu *popup = new QMenu(this);
651
    popup->addAction(tr("&Preview"), this, SLOT(menuPreview()));
652
    popup->addAction(tr("&Open"), this, SLOT(menuEdit()));
653
    popup->addAction(tr("Copy &File Name"), this, SLOT(menuCopyFN()));
654
    popup->addAction(tr("Copy &URL"), this, SLOT(menuCopyURL()));
655
    if (m_detaildoc.ipath.empty())
656
  popup->addAction(tr("&Write to File"), this, SLOT(menuSaveToFile()));
657
    popup->addAction(tr("Find &similar documents"), this, SLOT(menuExpand()));
658
    popup->addAction(tr("Preview P&arent document/folder"), 
659
            this, SLOT(menuPreviewParent()));
660
    popup->addAction(tr("&Open Parent document/folder"), 
661
            this, SLOT(menuOpenParent()));
662
    popup->popup(mapToGlobal(pos));
663
}
664
665
void ResTable::menuPreview()
666
{
667
    if (m_detaildocnum < 0) 
668
  return;
669
    emit docPreviewClicked(m_detaildocnum, m_detaildoc, 0);
670
}
671
672
void ResTable::menuSaveToFile()
673
{
674
    if (m_detaildocnum < 0) 
675
  return;
676
    emit docSaveToFileClicked(m_detaildoc);
677
}
678
679
void ResTable::menuPreviewParent()
680
{
681
    if (!m_model || m_detaildocnum < 0) 
682
  return;
683
    RefCntr<DocSequence> source = m_model->getDocSource();
684
    if (source.isNull())
685
  return;
686
    Rcl::Doc& doc = m_detaildoc;
687
    Rcl::Doc pdoc;
688
    if (source->getEnclosing(doc, pdoc)) {
689
  emit previewRequested(pdoc);
690
    } else {
691
  // No parent doc: show enclosing folder with app configured for
692
  // directories
693
  pdoc.url = path_getfather(doc.url);
694
  pdoc.mimetype = "application/x-fsdirectory";
695
  emit editRequested(pdoc);
696
    }
697
}
698
699
void ResTable::menuOpenParent()
700
{
701
    if (!m_model || m_detaildocnum < 0) 
702
  return;
703
    RefCntr<DocSequence> source = m_model->getDocSource();
704
    if (source.isNull())
705
  return;
706
    Rcl::Doc& doc = m_detaildoc;
707
    Rcl::Doc pdoc;
708
    if (source->getEnclosing(doc, pdoc)) {
709
  emit editRequested(pdoc);
710
    } else {
711
  // No parent doc: show enclosing folder with app configured for
712
  // directories
713
  pdoc.url = path_getfather(doc.url);
714
  pdoc.mimetype = "application/x-fsdirectory";
715
  emit editRequested(pdoc);
716
    }
717
}
718
719
void ResTable::menuEdit()
720
{
721
    if (m_detaildocnum < 0) 
722
  return;
723
    emit docEditClicked(m_detaildoc);
724
}
725
726
void ResTable::menuCopyFN()
727
{
728
    if (m_detaildocnum < 0) 
729
  return;
730
    Rcl::Doc &doc = m_detaildoc;
731
732
    // Our urls currently always begin with "file://" 
733
    //
734
    // Problem: setText expects a QString. Passing a (const char*)
735
    // as we used to do causes an implicit conversion from
736
    // latin1. File are binary and the right approach would be no
737
    // conversion, but it's probably better (less worse...) to
738
    // make a "best effort" tentative and try to convert from the
739
    // locale's charset than accept the default conversion.
740
    QString qfn = QString::fromLocal8Bit(doc.url.c_str()+7);
741
    QApplication::clipboard()->setText(qfn, QClipboard::Selection);
742
    QApplication::clipboard()->setText(qfn, QClipboard::Clipboard);
743
}
744
745
void ResTable::menuCopyURL()
746
{
747
    if (m_detaildocnum < 0) 
748
  return;
749
    Rcl::Doc &doc = m_detaildoc;
750
    string url =  url_encode(doc.url, 7);
751
    QApplication::clipboard()->setText(url.c_str(), 
752
                     QClipboard::Selection);
753
    QApplication::clipboard()->setText(url.c_str(), 
754
                     QClipboard::Clipboard);
755
}
756
757
void ResTable::menuExpand()
758
{
759
    if (m_detaildocnum < 0) 
760
  return;
761
    emit docExpand(m_detaildoc);
604
}
762
}
605
763
606
void ResTable::createHeaderPopupMenu(const QPoint& pos)
764
void ResTable::createHeaderPopupMenu(const QPoint& pos)
607
{
765
{
608
    LOGDEB(("ResTable::createHeaderPopupMenu(%d, %d)\n", pos.x(), pos.y()));
766
    LOGDEB(("ResTable::createHeaderPopupMenu(%d, %d)\n", pos.x(), pos.y()));