25 #include "ui_queryoptions.h"
31 #include <QApplication>
32 #include <QDesktopWidget>
34 #include <QSqlQueryModel>
37 #include <QButtonGroup>
40 #include <QDragEnterEvent>
41 #include <QSortFilterProxyModel>
42 #include <QStyledItemDelegate>
43 #include <QStringBuilder>
44 #include <QTextDocument>
46 #include <KColorScheme>
47 #include <kactioncategory.h>
50 #include <kstandarddirs.h>
51 #include <kxmlguifactory.h>
52 #include <threadweaver/ThreadWeaver.h>
54 #include <QStringListModel>
65 , m_queryType(WordOrder)
66 , m_totalResultCount(0)
68 setHeaderData(
TMDBModel::Source, Qt::Horizontal, i18nc(
"@title:column Original text",
"Source"));
69 setHeaderData(
TMDBModel::Target, Qt::Horizontal, i18nc(
"@title:column Text in target language",
"Target"));
86 bool invertSource,
bool invertTarget,
87 const QString& filemask
90 QString escapedSource(source);escapedSource.replace(
'\'',
"''");
91 QString escapedTarget(target);escapedTarget.replace(
'\'',
"''");
92 QString invertSourceStr;
if (invertSource) invertSourceStr=
"NOT ";
93 QString invertTargetStr;
if (invertTarget) invertTargetStr=
"NOT ";
94 QString escapedFilemask(filemask);escapedFilemask.replace(
'\'',
"''");
101 escapedSource.replace(
'%',
"\b%");escapedSource.replace(
'_',
"\b_");
102 escapedTarget.replace(
'%',
"\b%");escapedTarget.replace(
'_',
"\b_");
103 if (!escapedSource.isEmpty())
104 sourceQuery=
"AND source_strings.source "%invertSourceStr%
"LIKE '%"+escapedSource+
"%' ESCAPE '\b' ";
105 if (!escapedTarget.isEmpty())
106 targetQuery=
"AND target_strings.target "%invertTargetStr%
"LIKE '%"+escapedTarget+
"%' ESCAPE '\b' ";
112 QStringList sourceList=escapedSource.split(QRegExp(
"\\W"),QString::SkipEmptyParts);
113 QStringList targetList=escapedTarget.split(QRegExp(
"\\W"),QString::SkipEmptyParts);
115 if (!sourceList.isEmpty())
116 sourceQuery=
"AND source_strings.source "+invertSourceStr+
"LIKE '%"+sourceList.join(
"%' AND source_strings.source "+invertSourceStr+
"LIKE '%")+
"%' ";
117 if (!targetList.isEmpty())
118 targetQuery=
"AND target_strings.target "+invertTargetStr+
"LIKE '%"+targetList.join(
"%' AND target_strings.target "+invertTargetStr+
"LIKE '%")+
"%' ";
122 if (!escapedSource.isEmpty())
123 sourceQuery=
"AND source_strings.source "%invertSourceStr%
"GLOB '"%escapedSource%
"' ";
124 if (!escapedTarget.isEmpty())
125 targetQuery=
"AND target_strings.target "%invertTargetStr%
"GLOB '"%escapedTarget%
"' ";
128 if (!filemask.isEmpty())
129 fileQuery=
"AND files.path GLOB '"%escapedFilemask%
"' ";
131 QString fromPart=
"FROM main JOIN source_strings ON (source_strings.id=main.source) "
132 "JOIN target_strings ON (target_strings.id=main.target), files "
133 "WHERE files.id=main.file "
139 "SELECT source_strings.source, target_strings.target, "
140 "main.ctxt, files.path, "
141 "source_strings.source_accel, target_strings.target_accel, main.bits "
144 connect(job,SIGNAL(done(ThreadWeaver::Job*)),job,SLOT(deleteLater()));
145 connect(job,SIGNAL(done(ThreadWeaver::Job*)),
this,SLOT(
slotQueryExecuted(ThreadWeaver::Job*)));
146 ThreadWeaver::Weaver::instance()->enqueue(job);
149 job=
new ExecQueryJob(
"SELECT count(*) "+fromPart,m_dbName);
150 connect(job,SIGNAL(done(ThreadWeaver::Job*)),job,SLOT(deleteLater()));
151 connect(job,SIGNAL(done(ThreadWeaver::Job*)),
this,SLOT(
slotQueryExecuted(ThreadWeaver::Job*)));
152 ThreadWeaver::Weaver::instance()->enqueue(job);
154 m_totalResultCount=0;
160 if (job->
query->lastQuery().startsWith(
"SELECT count(*) "))
163 m_totalResultCount=job->
query->value(0).toInt();
167 setQuery(*(job->
query));
171 bool TMDBModel::rowIsApproved(
int row)
const
175 return !(ok && bits&4);
178 int TMDBModel::translationStatus(
const QModelIndex& item)
const
180 if (QSqlQueryModel::data(item.sibling(item.row(),
Target), Qt::DisplayRole).toString().isEmpty())
182 return int(!rowIsApproved(item.row()));
185 #define TM_DELIMITER '\v'
190 role=Qt::DisplayRole;
193 QFont font=QApplication::font();
194 font.setItalic(!rowIsApproved(item.row()));
198 return QSqlQueryModel::data(item, Qt::DisplayRole);
200 return translationStatus(item);
202 QVariant result=QSqlQueryModel::data(item, role);
205 if (role!=Qt::DisplayRole)
210 QString r=result.toString();
213 result=r.remove(pos, r.size());
220 if (posVar.isValid())
221 pos=posVar.toInt(&ok);
224 QString r=result.toString();
235 static QString statuses[]={i18nc(
"@info:status 'non-fuzzy' in gettext terminology",
"Ready"),
236 i18nc(
"@info:status 'fuzzy' in gettext terminology",
"Needs review"),
237 i18nc(
"@info:status",
"Untranslated")};
238 return statuses[translationStatus(item)];
252 TMResultsSortFilterProxyModel(
QObject *parent)
255 void setRules(
const QVector<Rule>& rules);
256 void fetchMore(
const QModelIndex& parent);
257 QVariant data(
const QModelIndex& index,
int role = Qt::DisplayRole)
const;
260 bool lessThan(
const QModelIndex& left,
const QModelIndex& right)
const;
261 bool filterAcceptsRow(
int source_row,
const QModelIndex& source_parent)
const;
264 QVector<Rule> m_rules;
265 mutable QMap<int,int> m_matchingRulesForSourceRow;
269 bool TMResultsSortFilterProxyModel::lessThan(
const QModelIndex& left,
const QModelIndex& right)
const
277 return QSortFilterProxyModel::lessThan(left, right);
280 void TMResultsSortFilterProxyModel::fetchMore(
const QModelIndex& parent)
282 int oldSourceRowCount=sourceModel()->rowCount();
283 int oldRowCount=rowCount();
284 QSortFilterProxyModel::fetchMore(parent);
286 if (m_rules.isEmpty())
289 while (oldRowCount==rowCount())
291 QSortFilterProxyModel::fetchMore(parent);
292 if (sourceModel()->rowCount()==oldSourceRowCount)
294 oldSourceRowCount=sourceModel()->rowCount();
296 qDebug()<<
"row count"<<sourceModel()->rowCount()<<
" filtered:"<<rowCount();
297 emit layoutChanged();
300 void TMResultsSortFilterProxyModel::setRules(
const QVector<Rule>& rules)
303 m_matchingRulesForSourceRow.clear();
307 QVariant TMResultsSortFilterProxyModel::data(
const QModelIndex& index,
int role)
const
309 QVariant result=QSortFilterProxyModel::data(index, role);
317 int source_row=mapToSource(index).row();
318 QString
string=result.toString();
320 QVector<QRegExp> regExps;
322 regExps=m_rules[m_matchingRulesForSourceRow[source_row]].sources;
324 regExps=m_rules[m_matchingRulesForSourceRow[source_row]].falseFriends;
326 foreach(
const QRegExp& re, regExps)
328 int pos=re.indexIn(
string);
330 return string.replace(pos, re.matchedLength(),
"<b>" % re.cap(0) %
"</b>");
338 bool TMResultsSortFilterProxyModel::filterAcceptsRow(
int source_row,
const QModelIndex& source_parent)
const
340 if (m_rules.isEmpty())
343 QString source=sourceModel()->index(source_row,
TMDBModel::Source, source_parent).data().toString();
344 QString target=sourceModel()->index(source_row,
TMDBModel::Target, source_parent).data().toString();
346 static QVector<StartLen> dummy_positions;
350 m_matchingRulesForSourceRow[source_row]=i;
359 explicit QueryStylesModel(
QObject* parent = 0);
360 QVariant data(
const QModelIndex& item,
int role)
const;
365 setStringList(QStringList(i18n(
"Substring"))<<i18n(
"Google-like")<<i18n(
"Wildcard"));
368 QVariant QueryStylesModel::data(
const QModelIndex& item,
int role)
const
370 if (role==Qt::ToolTipRole)
372 static QString tooltips[]={i18n(
"Case insensitive"),
373 i18n(
"Space is AND operator. Case insensitive."),
374 i18n(
"Shell globs (* and ?). Case sensitive.")};
375 return tooltips[item.row()];
377 return QStringListModel::data(item, role);
384 , m_proxyModel(new TMResultsSortFilterProxyModel(this))
389 setWindowTitle(i18nc(
"@title:window",
"Translation Memory"));
390 setAcceptDrops(
true);
392 ui_queryOptions=
new Ui_QueryOptions;
394 ui_queryOptions->setupUi(w);
396 ui_queryOptions->queryLayout->setStretchFactor(ui_queryOptions->mainQueryLayout,42);
398 connect(ui_queryOptions->querySource,SIGNAL(returnPressed()),
this,SLOT(
performQuery()));
399 connect(ui_queryOptions->queryTarget,SIGNAL(returnPressed()),
this,SLOT(
performQuery()));
400 connect(ui_queryOptions->filemask,SIGNAL(returnPressed()),
this,SLOT(
performQuery()));
401 connect(ui_queryOptions->doFind,SIGNAL(clicked()),
this,SLOT(
performQuery()));
402 connect(ui_queryOptions->doUpdateTM,SIGNAL(clicked()),
this,SLOT(
updateTM()));
404 QShortcut* sh=
new QShortcut(Qt::CTRL+Qt::Key_L,
this);
405 connect(sh,SIGNAL(activated()),ui_queryOptions->querySource,SLOT(setFocus()));
406 setFocusProxy(ui_queryOptions->querySource);
408 QTreeView* view=ui_queryOptions->treeView;
409 view->setContextMenuPolicy(Qt::ActionsContextMenu);
411 QAction* a=
new QAction(i18n(
"Copy source to clipboard"),view);
412 a->setShortcut(Qt::CTRL + Qt::Key_S);
413 a->setShortcutContext(Qt::WidgetWithChildrenShortcut);
414 connect(a,SIGNAL(activated()),
this, SLOT(
copySource()));
417 a=
new QAction(i18n(
"Copy target to clipboard"),view);
418 a->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
419 a->setShortcutContext(Qt::WidgetWithChildrenShortcut);
420 connect(a,SIGNAL(activated()),
this, SLOT(
copyTarget()));
423 a=
new QAction(i18n(
"Open file"),view);
424 a->setShortcut(QKeySequence(Qt::Key_Return));
425 a->setShortcutContext(Qt::WidgetWithChildrenShortcut);
426 connect(a,SIGNAL(activated()),
this, SLOT(
openFile()));
427 connect(view,SIGNAL(activated(QModelIndex)),
this, SLOT(
openFile()));
438 m_proxyModel->setDynamicSortFilter(
true);
439 m_proxyModel->setSourceModel(m_model);
440 view->setModel(m_proxyModel);
442 view->setSortingEnabled(
true);
456 connect(m_model,SIGNAL(resultsFetched()),view->itemDelegate(),SLOT(reset()));
457 connect(m_model,SIGNAL(modelReset()),view->itemDelegate(),SLOT(reset()));
459 connect(m_proxyModel,SIGNAL(layoutChanged()),view->itemDelegate(),SLOT(reset()));
463 connect(m_model,SIGNAL(resultsFetched()),
this,SLOT(
handleResults()));
466 ui_queryOptions->queryStyle->setModel(
new QueryStylesModel(
this));
467 connect(ui_queryOptions->queryStyle,SIGNAL(currentIndexChanged(
int)),m_model,SLOT(setQueryType(
int)));
474 ui_queryOptions->dbName->setCurrentIndex(pi->row());
475 ui_queryOptions->dbName->view()->setCurrentIndex(*pi);
477 connect(ui_queryOptions->dbName, SIGNAL(activated(QString)), m_model, SLOT(setDB(QString)));
481 static const int maxInitialWidths[4]={QApplication::desktop()->availableGeometry().width()/3,QApplication::desktop()->availableGeometry().width()/3, 50, 200};
482 int column=
sizeof(maxInitialWidths)/
sizeof(
int);
484 view->setColumnWidth(column, maxInitialWidths[column]);
492 setXMLFile(
"translationmemoryrui.rc",
true);
497 KActionCollection* ac=actionCollection();
498 KActionCategory* tm=
new KActionCategory(i18nc(
"@title actions category",
"Translation Memory"), ac);
500 action = tm->addAction(
"tools_tm_manage",
Project::instance(),SLOT(showTMManager()));
501 action->setText(i18nc(
"@action:inmenu",
"Manage translation memories"));
503 m_qaView =
new QaView(
this);
505 addDockWidget(Qt::RightDockWidgetArea, m_qaView);
506 tm->addAction( QLatin1String(
"showqa_action"), m_qaView->toggleViewAction() );
508 connect(m_qaView, SIGNAL(rulesChanged()),
this, SLOT(
setQAMode()));
509 connect(m_qaView->toggleViewAction(), SIGNAL(toggled(
bool)),
this, SLOT(
setQAMode(
bool)));
513 KConfigGroup cg(&config,
"MainWindow");
514 view->header()->restoreState(QByteArray::fromBase64( cg.readEntry(
"TMSearchResultsHeaderState", QByteArray()) ));
520 KConfigGroup cg(&config,
"MainWindow");
521 cg.writeEntry(
"TMSearchResultsHeaderState",ui_queryOptions->treeView->header()->saveState().toBase64());
523 delete ui_queryOptions;
524 ids.removeAll(m_dbusId);
536 m_model->
setFilter(ui_queryOptions->querySource->text(), ui_queryOptions->queryTarget->text(),
537 ui_queryOptions->invertSource->isChecked(), ui_queryOptions->invertTarget->isChecked(),
538 ui_queryOptions->filemask->text()
540 QApplication::setOverrideCursor(Qt::BusyCursor);
545 QApplication::restoreOverrideCursor();
546 QString filemask=ui_queryOptions->filemask->text();
548 int rowCount=m_model->rowCount();
551 kDebug()<<
"m_model->rowCount()==0";
557 QString text=ui_queryOptions->queryTarget->text();
559 text=ui_queryOptions->querySource->text();
566 KLineEdit*
const source_target_query[]={ui_queryOptions->queryTarget,ui_queryOptions->querySource};
569 m_partToAlsoTryLater=ui_queryOptions->filemask->text().isEmpty()?
574 if(!filemask.isEmpty() && !filemask.contains(
'*'))
576 ui_queryOptions->filemask->setText(
'*'+filemask+
'*');
580 kDebug()<<
"=DocPosition::UndefPart";
583 ui_queryOptions->treeView->setFocus();
589 int filtered=m_proxyModel->rowCount();
590 if (filtered==m_model->rowCount())
596 static void copy(Ui_QueryOptions* ui_queryOptions,
int column)
598 QApplication::clipboard()->setText( ui_queryOptions->treeView->currentIndex().sibling(ui_queryOptions->treeView->currentIndex().row(),column).data().toString());
613 QModelIndex item=ui_queryOptions->treeView->currentIndex();
627 m_proxyModel->setRules(QVector<Rule>());
631 m_proxyModel->setRules(m_qaView->
rules());
652 bool QueryResultDelegate::editorEvent(QEvent* event,
654 const QStyleOptionViewItem& ,
655 const QModelIndex& index)
657 kWarning()<<
"QEvent"<<event;
658 if (event->type()==QEvent::Shortcut)
660 kWarning()<<
"QEvent::Shortcut"<<index.data().canConvert(QVariant::String);
661 if (static_cast<QShortcutEvent*>(event)->key().matches(QKeySequence::Copy)
662 && index.data().canConvert(QVariant::String))
664 QApplication::clipboard()->setText(index.data().toString());
665 kWarning()<<
"index.data().toString()";
668 else if (event->type()==QEvent::MouseButtonRelease)
670 QMouseEvent* mEvent=
static_cast<QMouseEvent*
>(event);
671 if (mEvent->button()==Qt::MidButton)
675 else if (event->type()==QEvent::KeyPress)
677 QKeyEvent* kEvent=
static_cast<QKeyEvent*
>(event);
678 if (kEvent->key()==Qt::Key_Return)
680 if (kEvent->modifiers()==Qt::NoModifier)
698 void TMTab::dragEnterEvent(QDragEnterEvent* event)
701 event->acceptProposedAction();
704 void TMTab::dropEvent(QDropEvent *event)
707 event->acceptProposedAction();
710 #include "translationmemoryadaptor.h"
713 QList<int> TMTab::ids;
719 new TranslationMemoryAdaptor(
this);
722 while(i<ids.size()&&i==ids.at(i))
726 QDBusConnection::sessionBus().registerObject(
"/ThisIsWhatYouWant/TranslationMemory/" + QString::number(m_dbusId),
this);
729 return "/ThisIsWhatYouWant/TranslationMemory/" + QString::number(m_dbusId);
737 ui_queryOptions->querySource->setText(source);
738 ui_queryOptions->queryTarget->setText(target);
739 ui_queryOptions->invertSource->setChecked(
false);
740 ui_queryOptions->invertTarget->setChecked(
false);
753 kWarning()<<package<<text;
754 KLineEdit*
const source_target_query[]={ui_queryOptions->queryTarget,ui_queryOptions->querySource};
756 QTextCodec* latin1=QTextCodec::codecForMib(4);
761 ui_queryOptions->querySource->clear();
762 ui_queryOptions->queryTarget->clear();
764 ui_queryOptions->invertSource->setChecked(
false);
765 ui_queryOptions->invertTarget->setChecked(
false);
766 if (!package.isEmpty()) package=
'*'+package+
'*';
767 ui_queryOptions->filemask->setText(package);
QVector< Rule > rules() const
int scanRecursive(const QList< QUrl > &urls, const QString &dbName)
wrapper. returns gross number of jobs started
bool dragIsAcceptable(const QList< QUrl > &urls)
TMDBModel(QObject *parent)
void insert(int, const QString &)
int totalResultCount() const
static Project * instance()
QVariant data(const QModelIndex &item, int role=Qt::DisplayRole) const
void finalResultCountFetched(int)
void setQAMode(bool enabled=true)
This struct represents a position in a catalog.
static void copy(Ui_QueryOptions *ui_queryOptions, int column)
void setDB(const QString &)
void slotQueryExecuted(ThreadWeaver::Job *)
void fileOpenRequested(const KUrl &url, const QString &source, const QString &ctxt)
QPersistentModelIndex * projectDBIndex() const
remember to connect appropriate signals to reset slot for delegate to have actual cache ...
int findMatchingRule(const QVector< Rule > &rules, const QString &source, const QString &target, QVector< StartLen > &positions)
StatusBarProxy statusBarItems
Q_SCRIPTABLE void lookup(QString source, QString target)
QString projectID() const
Get ProjectID.
Q_SCRIPTABLE bool findGuiText(QString text)
QString convertToHtml(QString str, bool italics)
void setFilter(const QString &source, const QString &target, bool invertSource, bool invertTarget, const QString &filemask)
#define ID_STATUS_PROGRESS
void displayTotalResultCount()
QString shorterFilePath(const QString path)
Q_SCRIPTABLE bool findGuiTextPackage(QString text, QString package)
static DBFilesModel * instance()