diff --git a/src/cataloglistview/cataloglistview.cpp b/src/cataloglistview/cataloglistview.cpp index f1ce737..5909fac 100644 --- a/src/cataloglistview/cataloglistview.cpp +++ b/src/cataloglistview/cataloglistview.cpp @@ -1,330 +1,330 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2009 by Nick Shaforostoff 2018-2019 by Simon Depiets This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . **************************************************************************** */ #include "cataloglistview.h" #include "lokalize_debug.h" #include "catalogmodel.h" #include "catalog.h" #include "project.h" #include "prefs.h" #include "headerviewmenu.h" #include #include #include #include #include #include #include #include #include #include #include #include #include class CatalogTreeView: public QTreeView { public: CatalogTreeView(QWidget * parent) : QTreeView(parent) {} ~CatalogTreeView() {} protected: void keyReleaseEvent(QKeyEvent *e) override { if (e->key() == Qt::Key_Return && currentIndex().isValid()) { emit clicked(currentIndex()); e->accept(); } else { QTreeView::keyReleaseEvent(e); } } }; CatalogView::CatalogView(QWidget* parent, Catalog* catalog) : QDockWidget(i18nc("@title:window aka Message Tree", "Translation Units"), parent) , m_browser(new CatalogTreeView(this)) , m_lineEdit(new QLineEdit(this)) , m_model(new CatalogTreeModel(this, catalog)) , m_proxyModel(new CatalogTreeFilterModel(this)) { setObjectName(QStringLiteral("catalogTreeView")); QWidget* w = new QWidget(this); QVBoxLayout* layout = new QVBoxLayout(w); layout->setContentsMargins(0, 0, 0, 0); QHBoxLayout* l = new QHBoxLayout; l->setContentsMargins(0, 0, 0, 0); l->setSpacing(0); layout->addLayout(l); m_lineEdit->setClearButtonEnabled(true); m_lineEdit->setPlaceholderText(i18n("Quick search...")); m_lineEdit->setToolTip(i18nc("@info:tooltip", "Activated by Ctrl+L.") + ' ' + i18nc("@info:tooltip", "Accepts regular expressions")); connect(m_lineEdit, &QLineEdit::textChanged, this, &CatalogView::setFilterRegExp, Qt::QueuedConnection); // QShortcut* ctrlEsc=new QShortcut(QKeySequence(Qt::META+Qt::Key_Escape),this,SLOT(reset()),0,Qt::WidgetWithChildrenShortcut); QShortcut* esc = new QShortcut(QKeySequence(Qt::Key_Escape), this, 0, 0, Qt::WidgetWithChildrenShortcut); connect(esc, &QShortcut::activated, this, &CatalogView::escaped); QToolButton* btn = new QToolButton(w); btn->setPopupMode(QToolButton::InstantPopup); btn->setText(i18n("options")); //btn->setArrowType(Qt::DownArrow); btn->setMenu(new QMenu(this)); m_filterOptionsMenu = btn->menu(); connect(m_filterOptionsMenu, &QMenu::aboutToShow, this, &CatalogView::fillFilterOptionsMenu); connect(m_filterOptionsMenu, &QMenu::triggered, this, &CatalogView::filterOptionToggled); l->addWidget(m_lineEdit); l->addWidget(btn); layout->addWidget(m_browser); setTabOrder(m_lineEdit, btn); setTabOrder(btn, m_browser); setFocusProxy(m_lineEdit); setWidget(w); connect(m_browser, &CatalogTreeView::clicked, this, &CatalogView::slotItemActivated); m_browser->setRootIsDecorated(false); m_browser->setAllColumnsShowFocus(true); m_browser->setAlternatingRowColors(true); m_browser->viewport()->setBackgroundRole(QPalette::Background); #ifdef Q_OS_DARWIN QPalette p; p.setColor(QPalette::AlternateBase, p.color(QPalette::Background).darker(110)); p.setColor(QPalette::Highlight, p.color(QPalette::Background).darker(150)); m_browser->setPalette(p); #endif m_proxyModel->setSourceModel(m_model); m_browser->setModel(m_proxyModel); m_browser->setColumnWidth(0, m_browser->columnWidth(0) / 3); m_browser->setSortingEnabled(true); m_browser->sortByColumn(0, Qt::AscendingOrder); m_browser->setWordWrap(false); m_browser->setUniformRowHeights(true); m_browser->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); new HeaderViewMenuHandler(m_browser->header()); m_browser->header()->restoreState(readUiState("CatalogTreeViewState")); } CatalogView::~CatalogView() { writeUiState("CatalogTreeViewState", m_browser->header()->saveState()); } void CatalogView::setFocus() { QDockWidget::setFocus(); m_lineEdit->selectAll(); } void CatalogView::slotNewEntryDisplayed(const DocPosition& pos) { QModelIndex item = m_proxyModel->mapFromSource(m_model->index(pos.entry, 0)); m_browser->setCurrentIndex(item); m_browser->scrollTo(item/*,QAbstractItemView::PositionAtCenter*/); m_lastKnownDocPosition = pos.entry; } void CatalogView::setFilterRegExp() { QString expr = m_lineEdit->text(); if (m_proxyModel->filterRegExp().pattern() != expr) m_proxyModel->setFilterRegExp(m_proxyModel->filterOptions()&CatalogTreeFilterModel::IgnoreAccel ? expr.remove(Project::instance()->accel()) : expr); refreshCurrentIndex(); } void CatalogView::refreshCurrentIndex() { QModelIndex newPositionOfSelectedItem = m_proxyModel->mapFromSource(m_model->index(m_lastKnownDocPosition, 0)); m_browser->setCurrentIndex(newPositionOfSelectedItem); m_browser->scrollTo(newPositionOfSelectedItem); } void CatalogView::slotItemActivated(const QModelIndex& idx) { emit gotoEntry(DocPosition(m_proxyModel->mapToSource(idx).row()), 0); } void CatalogView::filterOptionToggled(QAction* action) { if (action->data().isNull()) return; int opt = action->data().toInt(); if (opt > 0) m_proxyModel->setFilterOptions(m_proxyModel->filterOptions()^opt); else { if (opt != -1) opt = -opt - 2; m_proxyModel->setFilterKeyColumn(opt); } m_filterOptionsMenu->clear(); refreshCurrentIndex(); } void CatalogView::fillFilterOptionsMenu() { m_filterOptionsMenu->clear(); if (m_proxyModel->individualRejectFilterEnabled()) m_filterOptionsMenu->addAction(i18n("Reset individual filter"), this, SLOT(setEntriesFilteredOut())); bool extStates = m_model->catalog()->capabilities()&ExtendedStates; const char* const basicTitles[] = { I18N_NOOP("Case insensitive"), I18N_NOOP("Ignore accelerator marks"), I18N_NOOP("Ready"), I18N_NOOP("Non-ready"), I18N_NOOP("Non-empty"), I18N_NOOP("Empty"), I18N_NOOP("Changed since file open"), I18N_NOOP("Unchanged since file open"), I18N_NOOP("Same in sync file"), I18N_NOOP("Different in sync file"), I18N_NOOP("Not in sync file"), I18N_NOOP("Plural"), I18N_NOOP("Non-plural"), }; const char* const* extTitles = Catalog::states(); const char* const* alltitles[2] = {basicTitles, extTitles}; QMenu* basicMenu = m_filterOptionsMenu->addMenu(i18nc("@title:inmenu", "Basic")); QMenu* extMenu = extStates ? m_filterOptionsMenu->addMenu(i18nc("@title:inmenu", "States")) : 0; QMenu* allmenus[2] = {basicMenu, extMenu}; QMenu* columnsMenu = m_filterOptionsMenu->addMenu(i18nc("@title:inmenu", "Searchable column")); QAction* txt; txt = m_filterOptionsMenu->addAction(i18nc("@title:inmenu", "Resort and refilter on content change"), m_proxyModel, &CatalogTreeFilterModel::setDynamicSortFilter); txt->setCheckable(true); txt->setChecked(m_proxyModel->dynamicSortFilter()); for (int i = 0; (1 << i) < CatalogTreeFilterModel::MaxOption; ++i) { bool ext = (1 << i) >= CatalogTreeFilterModel::New; if (!extStates && ext) break; txt = allmenus[ext]->addAction(i18n(alltitles[ext][i - ext * FIRSTSTATEPOSITION])); txt->setData(1 << i); txt->setCheckable(true); txt->setChecked(m_proxyModel->filterOptions() & (1 << i)); if ((1 << i) == CatalogTreeFilterModel::IgnoreAccel) basicMenu->addSeparator(); } if (!extStates) m_filterOptionsMenu->addSeparator(); - for (int i = -1; i < CatalogTreeModel::DisplayedColumnCount; ++i) { + for (int i = -1; i < CatalogTreeModel::DisplayedColumnCount-1; ++i) { qCWarning(LOKALIZE_LOG) << i; txt = columnsMenu->addAction((i == -1) ? i18nc("@item:inmenu all columns", "All") : m_model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString()); txt->setData(-i - 2); txt->setCheckable(true); txt->setChecked(m_proxyModel->filterKeyColumn() == i); } refreshCurrentIndex(); } void CatalogView::reset() { m_proxyModel->setFilterKeyColumn(-1); m_proxyModel->setFilterOptions(CatalogTreeFilterModel::AllStates); m_lineEdit->clear(); refreshCurrentIndex(); //emit gotoEntry(DocPosition(m_proxyModel->mapToSource(m_browser->currentIndex()).row()),0); slotItemActivated(m_browser->currentIndex()); } void CatalogView::setMergeCatalogPointer(MergeCatalog* pointer) { m_proxyModel->setMergeCatalogPointer(pointer); } int CatalogView::siblingEntryNumber(int step) { QModelIndex item = m_browser->currentIndex(); int lastRow = m_proxyModel->rowCount() - 1; if (!item.isValid()) { if (lastRow == -1) return -1; item = m_proxyModel->index((step == 1) ? 0 : lastRow, 0); m_browser->setCurrentIndex(item); } else { if (item.row() == ((step == -1) ? 0 : lastRow)) return -1; item = item.sibling(item.row() + step, 0); } return m_proxyModel->mapToSource(item).row(); } int CatalogView::nextEntryNumber() { return siblingEntryNumber(1); } int CatalogView::prevEntryNumber() { return siblingEntryNumber(-1); } static int edgeEntry(CatalogTreeFilterModel* m_proxyModel, int row) { if (!m_proxyModel->rowCount()) return -1; return m_proxyModel->mapToSource(m_proxyModel->index(row, 0)).row(); } int CatalogView::firstEntryNumber() { return edgeEntry(m_proxyModel, 0); } int CatalogView::lastEntryNumber() { return edgeEntry(m_proxyModel, m_proxyModel->rowCount() - 1); } void CatalogView::setEntryFilteredOut(int entry, bool filteredOut) { m_proxyModel->setEntryFilteredOut(entry, filteredOut); refreshCurrentIndex(); } void CatalogView::setEntriesFilteredOut(bool filteredOut) { show(); m_proxyModel->setEntriesFilteredOut(filteredOut); refreshCurrentIndex(); } diff --git a/src/cataloglistview/catalogmodel.cpp b/src/cataloglistview/catalogmodel.cpp index 4544b36..21e4bfc 100644 --- a/src/cataloglistview/catalogmodel.cpp +++ b/src/cataloglistview/catalogmodel.cpp @@ -1,355 +1,359 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2014 by Nick Shaforostoff 2018-2019 by Simon Depiets This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . **************************************************************************** */ #include "catalogmodel.h" #include "lokalize_debug.h" #include "catalog.h" #include "project.h" #include #include #include #include #include #include #define DYNAMICFILTER_LIMIT 256 QVector CatalogTreeModel::m_fonts; CatalogTreeModel::CatalogTreeModel(QObject* parent, Catalog* catalog) : QAbstractItemModel(parent) , m_catalog(catalog) , m_ignoreAccel(true) { if (m_fonts.isEmpty()) { QVector fonts(4, QApplication::font()); fonts[1].setItalic(true); //fuzzy fonts[2].setBold(true); //modified fonts[3].setItalic(true); //fuzzy fonts[3].setBold(true); //modified m_fonts.reserve(4); for (int i = 0; i < 4; i++) m_fonts << fonts.at(i); } connect(catalog, &Catalog::signalEntryModified, this, &CatalogTreeModel::reflectChanges); connect(catalog, QOverload<>::of(&Catalog::signalFileLoaded), this, &CatalogTreeModel::fileLoaded); } QModelIndex CatalogTreeModel::index(int row, int column, const QModelIndex& /*parent*/) const { return createIndex(row, column); } QModelIndex CatalogTreeModel::parent(const QModelIndex& /*index*/) const { return QModelIndex(); } int CatalogTreeModel::columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); return DisplayedColumnCount; } void CatalogTreeModel::fileLoaded() { beginResetModel(); endResetModel(); } void CatalogTreeModel::reflectChanges(DocPosition pos) { emit dataChanged(index(pos.entry, 0), index(pos.entry, DisplayedColumnCount - 1)); #if 0 I disabled dynamicSortFilter function //lazy sorting/filtering if (rowCount() < DYNAMICFILTER_LIMIT || m_prevChanged != pos) { qCWarning(LOKALIZE_LOG) << "first dataChanged emitment" << pos.entry; emit dataChanged(index(pos.entry, 0), index(pos.entry, DisplayedColumnCount - 1)); if (!(rowCount() < DYNAMICFILTER_LIMIT)) { qCWarning(LOKALIZE_LOG) << "second dataChanged emitment" << m_prevChanged.entry; emit dataChanged(index(m_prevChanged.entry, 0), index(m_prevChanged.entry, DisplayedColumnCount - 1)); } } m_prevChanged = pos; #endif } int CatalogTreeModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; return m_catalog->numberOfEntries(); } QVariant CatalogTreeModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const { if (role != Qt::DisplayRole) return QVariant(); switch (static_cast(section)) { case CatalogModelColumns::Key: return i18nc("@title:column", "Entry"); case CatalogModelColumns::Source: return i18nc("@title:column Original text", "Source"); case CatalogModelColumns::Target: return i18nc("@title:column Text in target language", "Target"); case CatalogModelColumns::Notes: return i18nc("@title:column", "Notes"); case CatalogModelColumns::Context: return i18nc("@title:column", "Context"); + case CatalogModelColumns::Files: + return i18nc("@title:column", "Files"); case CatalogModelColumns::TranslationStatus: return i18nc("@title:column", "Translation Status"); default: return {}; } } QVariant CatalogTreeModel::data(const QModelIndex& index, int role) const { if (m_catalog->numberOfEntries() <= index.row()) return QVariant(); const CatalogModelColumns column = static_cast(index.column()); if (role == Qt::SizeHintRole) { //no need to cache because of uniform row heights return QFontMetrics(QApplication::font()).size(Qt::TextSingleLine, QString::fromLatin1(" ")); } else if (role == Qt::FontRole/* && index.column()==Target*/) { bool fuzzy = !m_catalog->isApproved(index.row()); bool modified = m_catalog->isModified(index.row()); return m_fonts.at(fuzzy * 1 | modified * 2); } else if (role == Qt::ForegroundRole) { if (m_catalog->isBookmarked(index.row())) { static KColorScheme colorScheme(QPalette::Normal); return colorScheme.foreground(KColorScheme::LinkText); } if (m_catalog->isObsolete(index.row())) { static KColorScheme colorScheme(QPalette::Normal); return colorScheme.foreground(KColorScheme::InactiveText); } } else if (role == Qt::ToolTipRole) { if (column != CatalogModelColumns::TranslationStatus) { return {}; } switch (getTranslationStatus(index.row())) { case TranslationStatus::Ready: return i18nc("@info:status 'non-fuzzy' in gettext terminology", "Ready"); case TranslationStatus::NeedsReview: return i18nc("@info:status 'fuzzy' in gettext terminology", "Needs review"); case TranslationStatus::Untranslated: return i18nc("@info:status", "Untranslated"); } } else if (role == Qt::DecorationRole) { if (column != CatalogModelColumns::TranslationStatus) { return {}; } switch (getTranslationStatus(index.row())) { case TranslationStatus::Ready: return QIcon::fromTheme("emblem-checked"); case TranslationStatus::NeedsReview: return QIcon::fromTheme("emblem-question"); case TranslationStatus::Untranslated: return QIcon::fromTheme("emblem-unavailable"); } } else if (role == Qt::UserRole) { switch (column) { case CatalogModelColumns::TranslationStatus: return m_catalog->isApproved(index.row()); case CatalogModelColumns::IsEmpty: return m_catalog->isEmpty(index.row()); case CatalogModelColumns::State: return int(m_catalog->state(index.row())); case CatalogModelColumns::IsModified: return m_catalog->isModified(index.row()); case CatalogModelColumns::IsPlural: return m_catalog->isPlural(index.row()); default: role = Qt::DisplayRole; } } else if (role == StringFilterRole) { //exclude UI strings if (column >= CatalogModelColumns::TranslationStatus) return QVariant(); else if (column == CatalogModelColumns::Source || column == CatalogModelColumns::Target) { QString str = column == CatalogModelColumns::Source ? m_catalog->msgidWithPlurals(index.row(), false) : m_catalog->msgstrWithPlurals(index.row(), false); return m_ignoreAccel ? str.remove(Project::instance()->accel()) : str; } role = Qt::DisplayRole; } else if (role == SortRole) { //exclude UI strings if (column == CatalogModelColumns::TranslationStatus) { return static_cast(getTranslationStatus(index.row())); } role = Qt::DisplayRole; } if (role != Qt::DisplayRole) return QVariant(); switch (column) { case CatalogModelColumns::Key: return index.row() + 1; case CatalogModelColumns::Source: return m_catalog->msgidWithPlurals(index.row(), true); case CatalogModelColumns::Target: return m_catalog->msgstrWithPlurals(index.row(), true); case CatalogModelColumns::Notes: { QString result; foreach (const Note ¬e, m_catalog->notes(index.row())) result += note.content; return result; } case CatalogModelColumns::Context: return m_catalog->context(index.row()); + case CatalogModelColumns::Files: + return m_catalog->sourceFiles(index.row()).join('|'); default: return {}; } } CatalogTreeModel::TranslationStatus CatalogTreeModel::getTranslationStatus(int row) const { if (m_catalog->isEmpty(row)) { return CatalogTreeModel::TranslationStatus::Untranslated; } if (m_catalog->isApproved(row)) { return CatalogTreeModel::TranslationStatus::Ready; } else { return CatalogTreeModel::TranslationStatus::NeedsReview; } } CatalogTreeFilterModel::CatalogTreeFilterModel(QObject* parent) : QSortFilterProxyModel(parent) , m_filterOptions(AllStates) , m_individualRejectFilterEnable(false) , m_mergeCatalog(NULL) { setFilterKeyColumn(-1); setFilterCaseSensitivity(Qt::CaseInsensitive); setFilterRole(CatalogTreeModel::StringFilterRole); setSortRole(CatalogTreeModel::SortRole); setDynamicSortFilter(false); } void CatalogTreeFilterModel::setSourceModel(QAbstractItemModel* sourceModel) { QSortFilterProxyModel::setSourceModel(sourceModel); connect(sourceModel, &QAbstractItemModel::modelReset, this, QOverload<>::of(&CatalogTreeFilterModel::setEntriesFilteredOut)); setEntriesFilteredOut(false); } void CatalogTreeFilterModel::setEntriesFilteredOut() { return setEntriesFilteredOut(false); } void CatalogTreeFilterModel::setEntriesFilteredOut(bool filteredOut) { m_individualRejectFilter.fill(filteredOut, sourceModel()->rowCount()); m_individualRejectFilterEnable = filteredOut; invalidateFilter(); } void CatalogTreeFilterModel::setEntryFilteredOut(int entry, bool filteredOut) { // if (entry>=m_individualRejectFilter.size()) // sourceModelReset(); m_individualRejectFilter[entry] = filteredOut; m_individualRejectFilterEnable = true; invalidateFilter(); } void CatalogTreeFilterModel::setFilterOptions(int o) { m_filterOptions = o; setFilterCaseSensitivity(o & CaseInsensitive ? Qt::CaseInsensitive : Qt::CaseSensitive); static_cast(sourceModel())->setIgnoreAccel(o & IgnoreAccel); invalidateFilter(); } bool CatalogTreeFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const { int filerOptions = m_filterOptions; bool accepts = true; if (bool(filerOptions & Ready) != bool(filerOptions & NotReady)) { bool ready = sourceModel()->index(source_row, static_cast(CatalogTreeModel::CatalogModelColumns::TranslationStatus), source_parent).data(Qt::UserRole).toBool(); accepts = (ready == bool(filerOptions & Ready) || ready != bool(filerOptions & NotReady)); } if (accepts && bool(filerOptions & NonEmpty) != bool(filerOptions & Empty)) { bool untr = sourceModel()->index(source_row, static_cast(CatalogTreeModel::CatalogModelColumns::IsEmpty), source_parent).data(Qt::UserRole).toBool(); accepts = (untr == bool(filerOptions & Empty) || untr != bool(filerOptions & NonEmpty)); } if (accepts && bool(filerOptions & Modified) != bool(filerOptions & NonModified)) { bool modified = sourceModel()->index(source_row, static_cast(CatalogTreeModel::CatalogModelColumns::IsModified), source_parent).data(Qt::UserRole).toBool(); accepts = (modified == bool(filerOptions & Modified) || modified != bool(filerOptions & NonModified)); } if (accepts && bool(filerOptions & Plural) != bool(filerOptions & NonPlural)) { bool modified = sourceModel()->index(source_row, static_cast(CatalogTreeModel::CatalogModelColumns::IsPlural), source_parent).data(Qt::UserRole).toBool(); accepts = (modified == bool(filerOptions & Plural) || modified != bool(filerOptions & NonPlural)); } // These are the possible sync options of a row: // * SameInSync: The sync file contains a row with the same msgid and the same msgstr. // * DifferentInSync: The sync file contains a row with the same msgid and different msgstr. // * NotInSync: The sync file does not contain any row with the same msgid. // // The code below takes care of filtering rows when any of those options is not checked. // const int mask = (SameInSync | DifferentInSync | NotInSync); if (accepts && m_mergeCatalog && (filerOptions & mask) && (filerOptions & mask) != mask) { bool isPresent = m_mergeCatalog->isPresent(source_row); bool isDifferent = m_mergeCatalog->isDifferent(source_row); accepts = ! ((isPresent && !isDifferent && !bool(filerOptions & SameInSync)) || (isPresent && isDifferent && !bool(filerOptions & DifferentInSync)) || (!isPresent && !bool(filerOptions & NotInSync)) ); } if (accepts && (filerOptions & STATES) != STATES) { int state = sourceModel()->index(source_row, static_cast(CatalogTreeModel::CatalogModelColumns::State), source_parent).data(Qt::UserRole).toInt(); accepts = (filerOptions & (1 << (state + FIRSTSTATEPOSITION))); } accepts = accepts && !(m_individualRejectFilterEnable && source_row < m_individualRejectFilter.size() && m_individualRejectFilter.at(source_row)); return accepts && QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); } void CatalogTreeFilterModel::setMergeCatalogPointer(MergeCatalog* pointer) { m_mergeCatalog = pointer; } diff --git a/src/cataloglistview/catalogmodel.h b/src/cataloglistview/catalogmodel.h index 2cdb0ce..2b75f97 100644 --- a/src/cataloglistview/catalogmodel.h +++ b/src/cataloglistview/catalogmodel.h @@ -1,197 +1,198 @@ /* **************************************************************************** This file is part of Lokalize Copyright (C) 2007-2013 by Nick Shaforostoff 2018-2019 by Simon Depiets This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . **************************************************************************** */ #ifndef CATALOGMODEL_H #define CATALOGMODEL_H #include "mergecatalog.h" #include "pos.h" #include #include #include class Catalog; /** * MVC wrapper for Catalog */ class CatalogTreeModel: public QAbstractItemModel { Q_OBJECT public: enum class CatalogModelColumns { Key = 0, Source, Target, Notes, Context, + Files, TranslationStatus, IsEmpty, State, IsModified, IsPlural, ColumnCount, }; static const int DisplayedColumnCount = static_cast(CatalogModelColumns::TranslationStatus) + 1; // Possible values in column "Translation Status". enum class TranslationStatus { // translated Ready, // fuzzy NeedsReview, // empty Untranslated, }; enum Roles { StringFilterRole = Qt::UserRole + 1, SortRole = Qt::UserRole + 2, }; explicit CatalogTreeModel(QObject* parent, Catalog* catalog); ~CatalogTreeModel() override = default; QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex())const override; QModelIndex parent(const QModelIndex&) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex&, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation, int role = Qt::DisplayRole) const override; Catalog* catalog()const { return m_catalog; } void setIgnoreAccel(bool n) { m_ignoreAccel = n; } public slots: void reflectChanges(DocPosition); void fileLoaded(); private: TranslationStatus getTranslationStatus(int row) const; Catalog* m_catalog; bool m_ignoreAccel; static QVector m_fonts; //DocPos m_prevChanged; }; class CatalogTreeFilterModel: public QSortFilterProxyModel { Q_OBJECT public: enum FilterOptions { CaseInsensitive = 1 << 0, IgnoreAccel = 1 << 1, Ready = 1 << 2, NotReady = 1 << 3, NonEmpty = 1 << 4, Empty = 1 << 5, Modified = 1 << 6, NonModified = 1 << 7, SameInSync = 1 << 8, DifferentInSync = 1 << 9, NotInSync = 1 << 10, Plural = 1 << 11, NonPlural = 1 << 12, //states (see defines below) New = 1 << 13, NeedsTranslation = 1 << 14, NeedsL10n = 1 << 15, NeedsAdaptation = 1 << 16, Translated = 1 << 17, NeedsReviewTranslation = 1 << 18, NeedsReviewL10n = 1 << 19, NeedsReviewAdaptation = 1 << 20, Final = 1 << 21, SignedOff = 1 << 22, MaxOption = 1 << 23, AllStates = MaxOption - 1 }; #define STATES ((0xffff<<13)&(AllStates)) #define FIRSTSTATEPOSITION 13 explicit CatalogTreeFilterModel(QObject* parent); ~CatalogTreeFilterModel() {} bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override; void setFilterOptions(int o); int filterOptions()const { return m_filterOptions; } void setSourceModel(QAbstractItemModel* sourceModel) override; bool individualRejectFilterEnabled() { return m_individualRejectFilterEnable; } void setEntryFilteredOut(int entry, bool filteredOut); void setMergeCatalogPointer(MergeCatalog* pointer); public slots: void setEntriesFilteredOut(); void setEntriesFilteredOut(bool filteredOut); void setDynamicSortFilter(bool enabled) { QSortFilterProxyModel::setDynamicSortFilter(enabled); } private: int m_filterOptions; bool m_individualRejectFilterEnable; QVector m_individualRejectFilter; //used from kross scripts MergeCatalog* m_mergeCatalog; }; #endif