Warning, file /sdk/lokalize/src/phaseswindow.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 This file is part of Lokalize 0003 0004 SPDX-FileCopyrightText: 2009-2014 Nick Shaforostoff <shafff@ukr.net> 0005 SPDX-FileCopyrightText: 2018-2019 Simon Depiets <sdepiets@gmail.com> 0006 0007 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0008 */ 0009 0010 #include "phaseswindow.h" 0011 #include "catalog.h" 0012 #include "cmd.h" 0013 #include "noteeditor.h" 0014 #include "project.h" 0015 0016 #include <kcombobox.h> 0017 #include <klocalizedstring.h> 0018 #include <kstandardguiitem.h> 0019 0020 #include <QStringBuilder> 0021 #include <QPushButton> 0022 #include <QTextBrowser> 0023 #include <QTreeView> 0024 #include <QStringListModel> 0025 #include <QVBoxLayout> 0026 #include <QFormLayout> 0027 #include <QApplication> 0028 #include <QAbstractListModel> 0029 #include <QSplitter> 0030 #include <QStackedLayout> 0031 #include <QDialogButtonBox> 0032 0033 //BEGIN PhasesModel 0034 class PhasesModel: public QAbstractListModel 0035 { 0036 public: 0037 enum PhasesModelColumns { 0038 Date = 0, 0039 Process, 0040 Company, 0041 Contact, 0042 ToolName, 0043 ColumnCount 0044 }; 0045 0046 PhasesModel(Catalog* catalog, QObject* parent); 0047 ~PhasesModel() {} 0048 QModelIndex addPhase(const Phase& phase); 0049 QModelIndex activePhaseIndex()const 0050 { 0051 return index(m_activePhase); 0052 } 0053 QList<Phase> addedPhases()const; 0054 0055 int rowCount(const QModelIndex& parent = QModelIndex()) const override; 0056 int columnCount(const QModelIndex& parent = QModelIndex()) const override 0057 { 0058 Q_UNUSED(parent); 0059 return ColumnCount; 0060 } 0061 QVariant data(const QModelIndex&, int role = Qt::DisplayRole) const override; 0062 QVariant headerData(int section, Qt::Orientation, int role = Qt::DisplayRole) const override; 0063 0064 0065 private: 0066 Catalog* m_catalog; 0067 QList<Phase> m_phases; 0068 QMap<QString, Tool> m_tools; 0069 int m_activePhase; 0070 }; 0071 0072 PhasesModel::PhasesModel(Catalog* catalog, QObject* parent) 0073 : QAbstractListModel(parent) 0074 , m_catalog(catalog) 0075 , m_phases(catalog->allPhases()) 0076 , m_tools(catalog->allTools()) 0077 { 0078 m_activePhase = m_phases.size(); 0079 while (--m_activePhase >= 0 && m_phases.at(m_activePhase).name != catalog->activePhase()) 0080 ; 0081 } 0082 0083 QModelIndex PhasesModel::addPhase(const Phase& phase) 0084 { 0085 m_activePhase = m_phases.size(); 0086 beginInsertRows(QModelIndex(), m_activePhase, m_activePhase); 0087 m_phases.append(phase); 0088 endInsertRows(); 0089 return index(m_activePhase); 0090 } 0091 0092 QList<Phase> PhasesModel::addedPhases()const 0093 { 0094 QList<Phase> result; 0095 for (int i = m_catalog->allPhases().size(); i < m_phases.size(); ++i) 0096 result.append(m_phases.at(i)); 0097 0098 return result; 0099 } 0100 0101 int PhasesModel::rowCount(const QModelIndex& parent) const 0102 { 0103 if (parent.isValid()) 0104 return 0; 0105 return m_phases.size(); 0106 } 0107 0108 QVariant PhasesModel::data(const QModelIndex& index, int role) const 0109 { 0110 if (role == Qt::FontRole && index.row() == m_activePhase) { 0111 QFont font = QApplication::font(); 0112 font.setBold(true); 0113 return font; 0114 } 0115 if (role == Qt::UserRole) 0116 return m_phases.at(index.row()).name; 0117 if (role != Qt::DisplayRole) 0118 return QVariant(); 0119 0120 const Phase& phase = m_phases.at(index.row()); 0121 switch (index.column()) { 0122 case Date: return phase.date.toString(); 0123 case Process: return phase.process; 0124 case Company: return phase.company; 0125 case Contact: return QString(phase.contact 0126 % (phase.email.isEmpty() ? QString() : QStringLiteral(" <%1> ").arg(phase.email)) 0127 % (phase.phone.isEmpty() ? QString() : QStringLiteral(", %1").arg(phase.phone))); 0128 case ToolName: return m_tools.value(phase.tool).name; 0129 } 0130 return QVariant(); 0131 } 0132 0133 QVariant PhasesModel::headerData(int section, Qt::Orientation, int role) const 0134 { 0135 if (role != Qt::DisplayRole) 0136 return QVariant(); 0137 0138 switch (section) { 0139 case Date: return i18nc("@title:column", "Date"); 0140 case Process: return i18nc("@title:column", "Process"); 0141 case Company: return i18nc("@title:column", "Company"); 0142 case Contact: return i18nc("@title:column", "Person"); 0143 case ToolName: return i18nc("@title:column", "Tool"); 0144 } 0145 return QVariant(); 0146 } 0147 //END PhasesModel 0148 0149 0150 //BEGIN PhaseEditDialog 0151 class PhaseEditDialog: public QDialog 0152 { 0153 public: 0154 PhaseEditDialog(QWidget *parent); 0155 ~PhaseEditDialog() {} 0156 0157 Phase phase()const; 0158 ProjectLocal::PersonRole role()const; 0159 private: 0160 KComboBox* m_process; 0161 }; 0162 0163 0164 PhaseEditDialog::PhaseEditDialog(QWidget *parent) 0165 : QDialog(parent) 0166 , m_process(new KComboBox(this)) 0167 { 0168 QStringList processes; 0169 processes << i18n("Translation") << i18n("Review") << i18n("Approval"); 0170 m_process->setModel(new QStringListModel(processes, this)); 0171 0172 QFormLayout* l = new QFormLayout(this); 0173 l->addRow(i18nc("noun", "Process (this will also change your role):"), m_process); 0174 0175 QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); 0176 connect(buttonBox, &QDialogButtonBox::accepted, this, &PhaseEditDialog::accept); 0177 connect(buttonBox, &QDialogButtonBox::rejected, this, &PhaseEditDialog::reject); 0178 l->addRow(buttonBox); 0179 } 0180 0181 Phase PhaseEditDialog::phase() const 0182 { 0183 Phase phase; 0184 phase.process = processes()[m_process->currentIndex()]; 0185 return phase; 0186 } 0187 0188 ProjectLocal::PersonRole PhaseEditDialog::role() const 0189 { 0190 return (ProjectLocal::PersonRole)m_process->currentIndex(); 0191 } 0192 0193 0194 PhasesWindow::PhasesWindow(Catalog* catalog, QWidget *parent) 0195 : QDialog(parent) 0196 , m_catalog(catalog) 0197 , m_model(new PhasesModel(catalog, this)) 0198 , m_view(new MyTreeView(this)) 0199 , m_browser(new QTextBrowser(this)) 0200 , m_editor(nullptr) 0201 { 0202 connect(this, &PhasesWindow::accepted, this, &PhasesWindow::handleResult); 0203 //setAttribute(Qt::WA_DeleteOnClose, true); 0204 QVBoxLayout* l = new QVBoxLayout(this); 0205 QHBoxLayout* btns = new QHBoxLayout; 0206 l->addLayout(btns); 0207 0208 QPushButton* add = new QPushButton(this); 0209 KGuiItem::assign(add, KStandardGuiItem::add()); 0210 0211 connect(add, &QPushButton::clicked, this, &PhasesWindow::addPhase); 0212 btns->addWidget(add); 0213 btns->addStretch(5); 0214 0215 QSplitter* splitter = new QSplitter(this); 0216 l->addWidget(splitter); 0217 0218 m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); 0219 connect(m_buttonBox, &QDialogButtonBox::accepted, this, &PhasesWindow::accept); 0220 connect(m_buttonBox, &QDialogButtonBox::rejected, this, &PhasesWindow::reject); 0221 l->addWidget(m_buttonBox); 0222 0223 0224 m_view->setRootIsDecorated(false); 0225 m_view->setModel(m_model); 0226 splitter->addWidget(m_view); 0227 int column = m_model->columnCount(); 0228 while (--column >= 0) 0229 m_view->resizeColumnToContents(column); 0230 if (m_model->rowCount()) 0231 m_view->setCurrentIndex(m_model->activePhaseIndex()); 0232 connect(m_view, &MyTreeView::currentIndexChanged, this, &PhasesWindow::displayPhaseNotes); 0233 0234 0235 m_noteView = new QWidget(this); 0236 m_noteView->hide(); 0237 splitter->addWidget(m_noteView); 0238 m_stackedLayout = new QStackedLayout(m_noteView); 0239 m_stackedLayout->addWidget(m_browser); 0240 0241 m_browser->viewport()->setBackgroundRole(QPalette::Window); 0242 m_browser->setOpenLinks(false); 0243 connect(m_browser, &QTextBrowser::anchorClicked, this, &PhasesWindow::anchorClicked); 0244 0245 splitter->setStretchFactor(0, 15); 0246 splitter->setStretchFactor(1, 5); 0247 resize(QSize(700, 400)); 0248 } 0249 0250 void PhasesWindow::handleResult() 0251 { 0252 m_catalog->beginMacro(i18nc("@item Undo action item", "Edit phases")); 0253 0254 Phase last; 0255 const auto addedPhases = m_model->addedPhases(); 0256 for (const Phase& phase : addedPhases) 0257 static_cast<QUndoStack*>(m_catalog)->push(new UpdatePhaseCmd(m_catalog, last = phase)); 0258 Project::instance()->local()->setRole(roleForProcess(last.process)); 0259 m_catalog->setActivePhase(last.name, roleForProcess(last.process)); 0260 0261 QMapIterator<QString, QVector<Note> > i(m_phaseNotes); 0262 while (i.hasNext()) { 0263 i.next(); 0264 m_catalog->setPhaseNotes(i.key(), i.value()); 0265 } 0266 0267 m_catalog->endMacro(); 0268 } 0269 0270 void PhasesWindow::addPhase() 0271 { 0272 PhaseEditDialog d(this); 0273 if (!d.exec()) 0274 return; 0275 0276 Phase phase = d.phase(); 0277 initPhaseForCatalog(m_catalog, phase, ForceAdd); 0278 m_view->setCurrentIndex(m_model->addPhase(phase)); 0279 m_phaseNotes.insert(phase.name, QVector<Note>()); 0280 0281 m_buttonBox->button(QDialogButtonBox::Ok)->setFocus(); 0282 } 0283 0284 static QString phaseNameFromView(QTreeView* view) 0285 { 0286 return view->currentIndex().data(Qt::UserRole).toString(); 0287 } 0288 0289 void PhasesWindow::anchorClicked(QUrl link) 0290 { 0291 QString path = link.path().mid(1); // minus '/' 0292 0293 if (link.scheme() == QLatin1String("note")) { 0294 if (!m_editor) { 0295 m_editor = new NoteEditor(this); 0296 m_stackedLayout->addWidget(m_editor); 0297 connect(m_editor, &NoteEditor::accepted, this, &PhasesWindow::noteEditAccepted); 0298 connect(m_editor, &NoteEditor::rejected, this, &PhasesWindow::noteEditRejected); 0299 } 0300 m_editor->setNoteAuthors(m_catalog->noteAuthors()); 0301 if (path.endsWith(QLatin1String("add"))) 0302 m_editor->setNote(Note(), -1); 0303 else { 0304 int pos = path.toInt(); 0305 QString phaseName = phaseNameFromView(m_view); 0306 QVector<Note> notes = m_phaseNotes.contains(phaseName) ? 0307 m_phaseNotes.value(phaseName) 0308 : m_catalog->phaseNotes(phaseName); 0309 m_editor->setNote(notes.at(pos), pos); 0310 } 0311 m_stackedLayout->setCurrentIndex(1); 0312 } 0313 } 0314 0315 void PhasesWindow::noteEditAccepted() 0316 { 0317 QString phaseName = phaseNameFromView(m_view); 0318 if (!m_phaseNotes.contains(phaseName)) 0319 m_phaseNotes.insert(phaseName, m_catalog->phaseNotes(phaseName)); 0320 0321 //QVector<Note> notes=m_phaseNotes.value(phaseName); 0322 if (m_editor->noteIndex() == -1) 0323 m_phaseNotes[phaseName].append(m_editor->note()); 0324 else 0325 m_phaseNotes[phaseName][m_editor->noteIndex()] = m_editor->note(); 0326 0327 m_stackedLayout->setCurrentIndex(0); 0328 displayPhaseNotes(m_view->currentIndex()); 0329 } 0330 0331 void PhasesWindow::noteEditRejected() 0332 { 0333 m_stackedLayout->setCurrentIndex(0); 0334 } 0335 0336 void PhasesWindow::displayPhaseNotes(const QModelIndex& current) 0337 { 0338 m_browser->clear(); 0339 QString phaseName = current.data(Qt::UserRole).toString(); 0340 QVector<Note> notes = m_phaseNotes.contains(phaseName) ? 0341 m_phaseNotes.value(phaseName) 0342 : m_catalog->phaseNotes(phaseName); 0343 displayNotes(m_browser, notes); 0344 m_noteView->show(); 0345 m_stackedLayout->setCurrentIndex(0); 0346 } 0347