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