Warning, file /office/calligra/libs/rdf/KoSopranoTableModel.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 Copyright (C) 2010 KO GmbH <ben.martin@kogmbh.com> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "KoSopranoTableModel.h" 0021 0022 #include "KoDocumentRdf.h" 0023 #include "KoRdfPrefixMapping.h" 0024 // KF5 0025 #include <kdebug.h> 0026 #include <klocalizedstring.h> 0027 0028 #include <algorithm> 0029 0030 KoSopranoTableModel::KoSopranoTableModel(KoDocumentRdf *rdf) 0031 : m_rdf(rdf) 0032 { 0033 Soprano::StatementIterator siter = model()->listStatements(); 0034 while (siter.next()) { 0035 m_statementIndex << *siter; 0036 } 0037 } 0038 0039 QSharedPointer<Soprano::Model> KoSopranoTableModel::model() const 0040 { 0041 return m_rdf->model(); 0042 } 0043 0044 QString KoSopranoTableModel::URItoPrefexedLocalname(const QString &uri) const 0045 { 0046 return m_rdf->prefixMapping()->URItoPrefexedLocalname(uri); 0047 } 0048 QString KoSopranoTableModel::PrefexedLocalnameToURI(const QString &pname) 0049 { 0050 return m_rdf->prefixMapping()->PrefexedLocalnameToURI(pname); 0051 } 0052 0053 QVariant KoSopranoTableModel::data(const QModelIndex &index, int role) const 0054 { 0055 if (!index.isValid()) { 0056 return QVariant(); 0057 } 0058 Soprano::Statement st = m_statementIndex[index.row()]; 0059 if (index.column() == ColIsValid && role == Qt::CheckStateRole) { 0060 return st.isValid(); 0061 } 0062 if (role == Qt::BackgroundRole) { 0063 if (!m_statementIndex[index.row()].isValid()) { 0064 return QColor("#BB0000"); 0065 } 0066 } 0067 if (role != Qt::DisplayRole && role != Qt::EditRole) { 0068 return QVariant(); 0069 } 0070 switch (index.column()) { 0071 case ColIsValid: 0072 return QVariant(); 0073 case ColSubj: 0074 return URItoPrefexedLocalname(st.subject().toString()); 0075 case ColPred: 0076 return URItoPrefexedLocalname(st.predicate().toString()); 0077 case ColObj: 0078 if (st.object().type() == Soprano::Node::ResourceNode) 0079 return URItoPrefexedLocalname(st.object().toString()); 0080 return st.object().toString(); 0081 case ColObjType: 0082 switch (st.object().type()) { 0083 case Soprano::Node::EmptyNode: 0084 return i18n("Empty"); 0085 case Soprano::Node::ResourceNode: 0086 return i18n("URI"); 0087 case Soprano::Node::LiteralNode: 0088 return i18n("Literal"); 0089 case Soprano::Node::BlankNode: 0090 return i18n("Blank"); 0091 } 0092 return QString(); 0093 case ColObjXsdType: 0094 return st.object().dataType().toString(); 0095 case ColCtx: { 0096 QString ctx = st.context().toString(); 0097 QString RdfPathContextPrefix = m_rdf->RDF_PATH_CONTEXT_PREFIX; 0098 QString InternalContext = m_rdf->inlineRdfContext().toString(); 0099 0100 kDebug(30015) << "InternalContext:" << InternalContext; 0101 kDebug(30015) << "ctx:" << ctx; 0102 0103 if (ctx.startsWith(RdfPathContextPrefix)) { 0104 ctx.remove(0, RdfPathContextPrefix.size()); 0105 } 0106 if (isInlineRdf(st)) { 0107 ctx = "inline"; 0108 } 0109 return ctx; 0110 } 0111 } 0112 return QVariant(); 0113 } 0114 0115 int KoSopranoTableModel::rowCount(const QModelIndex &parent) const 0116 { 0117 Q_UNUSED(parent); 0118 return model()->statementCount(); 0119 } 0120 0121 int KoSopranoTableModel::columnCount(const QModelIndex &parent) const 0122 { 0123 Q_UNUSED(parent); 0124 return ColCount; 0125 } 0126 0127 QVariant KoSopranoTableModel::headerData(int section, Qt::Orientation orientation, int role) const 0128 { 0129 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { 0130 switch (section) { 0131 case ColIsValid: 0132 return i18n("Valid"); 0133 case ColSubj: 0134 return i18n("Subject"); 0135 case ColPred: 0136 return i18n("Predicate"); 0137 case ColObj: 0138 return i18n("Object"); 0139 case ColObjType: 0140 return i18n("Obj Type"); 0141 case ColObjXsdType: 0142 return i18n("DataType"); 0143 case ColCtx: 0144 return i18n("Stored In"); 0145 } 0146 } 0147 return QVariant(); 0148 } 0149 0150 bool KoSopranoTableModel::isInlineRdf(const Soprano::Statement &st) const 0151 { 0152 return (st.context().toString() == m_rdf->inlineRdfContext().toString()); 0153 } 0154 0155 Qt::ItemFlags KoSopranoTableModel::flags(const QModelIndex &index) const 0156 { 0157 Qt::ItemFlags ret = QAbstractTableModel::flags(index) | Qt::ItemIsEditable; 0158 if (index.column() == ColIsValid) { 0159 ret |= Qt::ItemIsUserCheckable; 0160 } 0161 if (index.row() >= 0) { 0162 Soprano::Statement st = m_statementIndex[index.row()]; 0163 if (isInlineRdf(st)) { 0164 if (index.column() == ColSubj 0165 || index.column() == ColObjType 0166 || index.column() == ColCtx) { 0167 ret &= (~Qt::ItemIsEditable); 0168 } 0169 } 0170 } 0171 return ret; 0172 } 0173 0174 /** 0175 * You MUST use this method if you want to change a Statement. 0176 * 0177 * Used by setData() to remove the old statement and replace it with the new 'n' one. 0178 * The internal m_statementIndex int->statement is updated 0179 * as well as the dataChanged signal emitted 0180 */ 0181 bool KoSopranoTableModel::setDataUpdateTriple(const QModelIndex &index, const Soprano::Statement &old, const Soprano::Statement &n) 0182 { 0183 model()->addStatement(n); 0184 model()->removeStatement(old); 0185 m_statementIndex[index.row()] = n; 0186 emit dataChanged(index, index); 0187 return true; 0188 } 0189 0190 bool KoSopranoTableModel::setData(const QModelIndex &index, const QVariant &value, int role) 0191 { 0192 Q_UNUSED(role); 0193 if (!index.isValid()) { 0194 return false; 0195 } 0196 int r = index.row(); 0197 Soprano::Statement st = m_statementIndex[r]; 0198 QString uri = PrefexedLocalnameToURI(value.toString()); 0199 Soprano::Statement n(st.subject(), st.predicate(), st.object(), st.context()); 0200 switch (index.column()) { 0201 case ColSubj: 0202 n.setSubject(Soprano::Node(QUrl(uri))); 0203 return setDataUpdateTriple(index, st, n); 0204 case ColPred: 0205 n.setPredicate(Soprano::Node(QUrl(uri))); 0206 return setDataUpdateTriple(index, st, n); 0207 case ColObj: { 0208 if (st.object().isLiteral()) { 0209 n.setObject( 0210 Soprano::Node( 0211 Soprano::LiteralValue(value.toString()))); 0212 } else { 0213 n.setObject(Soprano::Node(QUrl(uri))); 0214 } 0215 return setDataUpdateTriple(index, st, n); 0216 } 0217 case ColObjType: { 0218 QString v = value.toString(); 0219 if (v == "URI") { 0220 n.setObject(Soprano::Node(QUrl(st.object().toString()))); 0221 } else if (v == "Literal") { 0222 n.setObject( 0223 Soprano::Node( 0224 Soprano::LiteralValue(st.object().toString()))); 0225 } else { 0226 n.setObject(Soprano::Node(QString(st.object().toString()))); 0227 } 0228 return setDataUpdateTriple(index, st, n); 0229 } 0230 case ColCtx: { 0231 QString v = value.toString(); 0232 if (v == "inline") { 0233 QString InternalContext = m_rdf->rdfInternalMetadataWithoutSubjectURI(); 0234 n.setContext(Soprano::Node(QUrl(InternalContext))); 0235 } else { 0236 if (!v.endsWith(".rdf")) 0237 v = v + ".rdf"; 0238 n.setContext(Soprano::Node(QUrl(m_rdf->RDF_PATH_CONTEXT_PREFIX + v))); 0239 } 0240 return setDataUpdateTriple(index, st, n); 0241 } 0242 } 0243 return false; 0244 } 0245 0246 /** 0247 * Add the statement 'st' to the model as the new last row. 0248 */ 0249 int KoSopranoTableModel::insertStatement(const Soprano::Statement &st) 0250 { 0251 QModelIndex parent; 0252 int newRowNumber = rowCount(); 0253 kDebug(30015) << "insert, newrow:" << newRowNumber << endl; 0254 beginInsertRows(parent, newRowNumber, newRowNumber); 0255 model()->addStatement(st); 0256 m_statementIndex << st; 0257 endInsertRows(); 0258 return newRowNumber; 0259 } 0260 0261 /** 0262 * Copy all the triples in srclist to be new rows in the model. 0263 * Note that the object value is modified to contain a unique 0264 * postfix so that the new triple copies can be inserted into 0265 * the Rdf model. It is a copy in a looser sense of the word. 0266 */ 0267 QModelIndexList KoSopranoTableModel::copyTriples(const QModelIndexList &srclist) 0268 { 0269 QModelIndexList ret; 0270 int FirstNewRowNumber = rowCount(); 0271 int LastNewRowNumber = FirstNewRowNumber + srclist.size() - 1; 0272 int currentNewRowNum = FirstNewRowNumber; 0273 beginInsertRows(QModelIndex(), FirstNewRowNumber, LastNewRowNumber); 0274 kDebug(30015) << " m_statementIndex.sz:" << m_statementIndex.size(); 0275 kDebug(30015) << " srclist.size():" << srclist.size(); 0276 kDebug(30015) << " first:" << FirstNewRowNumber; 0277 kDebug(30015) << " last:" << LastNewRowNumber; 0278 foreach (const QModelIndex &src, srclist) { 0279 int r = src.row(); 0280 kDebug(30015) << "r:" << r; 0281 Soprano::Statement st = m_statementIndex[ r ]; 0282 // 0283 // Append a bnode to the object to ensure the "copy" 0284 // is unique relative to the original. 0285 // 0286 Soprano::Node obj(QUrl(st.object().toString() + '-' 0287 + model()->createBlankNode().toString())); 0288 Soprano::Statement n(st.subject(), st.predicate(), 0289 obj, st.context()); 0290 model()->addStatement(n); 0291 m_statementIndex << n; 0292 QModelIndex newIdx = index(currentNewRowNum, ColSubj); 0293 ret << newIdx; 0294 ++currentNewRowNum; 0295 } 0296 endInsertRows(); 0297 return ret; 0298 } 0299 0300 /** 0301 * Delete all the triples in srclist from the model. 0302 */ 0303 void KoSopranoTableModel::deleteTriples(const QModelIndexList &srclist) 0304 { 0305 // 0306 // Because items after a row are shuffled back to fill 0307 // it's position, it is easiest to remove each item 0308 // starting at the largest row number and working 0309 // down by descending row number. 0310 // 0311 QList<int> rowsToRemoveDesc; 0312 foreach (const QModelIndex &src, srclist) { 0313 int r = src.row(); 0314 rowsToRemoveDesc << r; 0315 } 0316 std:sort(rowsToRemoveDesc.begin(), rowsToRemoveDesc.end(), std::greater<int>()); 0317 int r; 0318 foreach (r, rowsToRemoveDesc) { 0319 Soprano::Statement st = m_statementIndex[ r ]; 0320 int firstRow = r; 0321 int lastRow = r; 0322 beginRemoveRows(QModelIndex(), firstRow, lastRow); 0323 model()->removeStatement(st); 0324 // m_statementIndex[ r ] = Soprano::Statement(); 0325 for (int i = r; i < m_statementIndex.size() - 1; ++i) { 0326 m_statementIndex[ i ] = m_statementIndex[ i + 1 ]; 0327 } 0328 m_statementIndex.removeLast(); 0329 endRemoveRows(); 0330 } 0331 } 0332 0333 Soprano::Statement KoSopranoTableModel::statementAtIndex(const QModelIndex &index) const 0334 { 0335 return m_statementIndex[index.row()]; 0336 } 0337 0338 int KoSopranoTableModel::invalidStatementCount() const 0339 { 0340 return invalidStatementList().size(); 0341 } 0342 0343 QModelIndexList KoSopranoTableModel::invalidStatementList() const 0344 { 0345 QModelIndexList ret; 0346 for (int r = 0; r < m_statementIndex.size(); ++r) { 0347 const Soprano::Statement &s = m_statementIndex.at(r); 0348 if (!s.isValid()) { 0349 int col = ColSubj; 0350 if (!s.subject().isValid()) { 0351 col = ColSubj; 0352 } 0353 if (!s.predicate().isValid()) { 0354 col = ColPred; 0355 } 0356 if (!s.object().isValid()) { 0357 col = ColObj; 0358 } 0359 QModelIndex idx = index(r, col); 0360 ret << idx; 0361 } 0362 } 0363 return ret; 0364 } 0365