File indexing completed on 2024-04-21 04:54:12
0001 /* 0002 SPDX-FileCopyrightText: 2011 Koos Vriezen <koos.vriezen@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #include "playmodel.h" 0008 #include "playlistview.h" 0009 #include "kmplayercommon_log.h" 0010 0011 #include <QPixmap> 0012 #include <QTimer> 0013 0014 #include <KLocalizedString> 0015 #include <KIconLoader> 0016 0017 using namespace KMPlayer; 0018 0019 TopPlayItem *PlayItem::rootItem () 0020 { 0021 PlayItem *r = nullptr; 0022 for (PlayItem *p = this; p->parent_item; p = p->parent_item) 0023 r = p; 0024 return static_cast <TopPlayItem *> (r); 0025 } 0026 0027 Qt::ItemFlags TopPlayItem::itemFlags () 0028 { 0029 Qt::ItemFlags itemflags = Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled; 0030 if (root_flags & PlayModel::AllowDrag) 0031 itemflags |= Qt::ItemIsDragEnabled; 0032 if (root_flags & PlayModel::InPlaceEdit) 0033 itemflags |= Qt::ItemIsEditable; 0034 return itemflags; 0035 } 0036 0037 //----------------------------------------------------------------------------- 0038 0039 struct TreeUpdate { 0040 TreeUpdate (TopPlayItem *ri, NodePtr n, bool s, bool o, SharedPtr <TreeUpdate> &nx) : root_item (ri), node (n), select (s), open (o), next (nx) {} 0041 ~TreeUpdate () {} 0042 TopPlayItem * root_item; 0043 NodePtrW node; 0044 bool select; 0045 bool open; 0046 SharedPtr <TreeUpdate> next; 0047 }; 0048 0049 PlayModel::PlayModel (QObject *parent, KIconLoader *loader) 0050 : QAbstractItemModel (parent), 0051 auxiliary_pix (loader->loadIcon (QString ("folder-grey"), KIconLoader::Small)), 0052 config_pix (loader->loadIcon (QString ("configure"), KIconLoader::Small)), 0053 folder_pix (loader->loadIcon (QString ("folder"), KIconLoader::Small)), 0054 img_pix (loader->loadIcon (QString ("image-png"), KIconLoader::Small)), 0055 info_pix (loader->loadIcon (QString ("dialog-info"), KIconLoader::Small)), 0056 menu_pix (loader->loadIcon (QString ("view-media-playlist"), KIconLoader::Small)), 0057 unknown_pix (loader->loadIcon (QString ("unknown"), KIconLoader::Small)), 0058 url_pix (loader->loadIcon (QString ("internet-web-browser"), KIconLoader::Small)), 0059 video_pix (loader->loadIcon (QString ("video-x-generic"), KIconLoader::Small)), 0060 root_item (new PlayItem ((Node *)nullptr, nullptr)), 0061 last_id (0) 0062 { 0063 TopPlayItem *ritem = new TopPlayItem (this, 0064 0, nullptr, PlayModel::AllowDrops | PlayModel::TreeEdit); 0065 ritem->parent_item = root_item; 0066 root_item->child_items.append (ritem); 0067 ritem->icon = url_pix; 0068 } 0069 0070 PlayModel::~PlayModel () 0071 { 0072 delete root_item; 0073 } 0074 0075 QVariant PlayModel::data (const QModelIndex &index, int role) const 0076 { 0077 if (!index.isValid ()) 0078 return QVariant (); 0079 0080 PlayItem *item = static_cast<PlayItem*> (index.internalPointer ()); 0081 switch (role) { 0082 case Qt::DisplayRole: 0083 return item->title; 0084 0085 case Qt::DecorationRole: 0086 if (item->parent () == root_item) 0087 return static_cast <TopPlayItem *> (item)->icon; 0088 if (item->attribute) 0089 return config_pix; 0090 if (item->childCount() > 0) 0091 if (item->child (0)->attribute) 0092 return menu_pix; 0093 if (item->node) { 0094 Node::PlayType pt = item->node->playType (); 0095 switch (pt) { 0096 case Node::play_type_image: 0097 return img_pix; 0098 case Node::play_type_info: 0099 return info_pix; 0100 default: 0101 if (pt > Node::play_type_none) 0102 return video_pix; 0103 else 0104 return item->childCount () 0105 ? item->node->auxiliaryNode () 0106 ? auxiliary_pix : folder_pix 0107 : unknown_pix; 0108 } 0109 } 0110 return unknown_pix; 0111 0112 case UrlRole: 0113 if (item->node) { 0114 Mrl *mrl = item->node->mrl (); 0115 if (mrl && !mrl->src.isEmpty ()) 0116 return mrl->src; 0117 } 0118 return QVariant (); 0119 0120 case Qt::EditRole: 0121 if (item->item_flags & Qt::ItemIsEditable) 0122 return item->title; 0123 Q_FALLTHROUGH(); 0124 0125 default: 0126 return QVariant (); 0127 } 0128 } 0129 0130 bool PlayModel::setData (const QModelIndex& i, const QVariant& v, int role) 0131 { 0132 if (role != Qt::EditRole || !i.isValid ()) 0133 return false; 0134 0135 bool changed = false; 0136 PlayItem *item = static_cast <PlayItem *> (i.internalPointer ()); 0137 QString ntext = v.toString (); 0138 0139 TopPlayItem *ri = item->rootItem (); 0140 if (ri->show_all_nodes && item->attribute) { 0141 int pos = ntext.indexOf (QChar ('=')); 0142 if (pos > -1) { 0143 item->attribute->setName (ntext.left (pos)); 0144 item->attribute->setValue (ntext.mid (pos + 1)); 0145 } else { 0146 item->attribute->setName (ntext); 0147 item->attribute->setValue (QString ("")); 0148 } 0149 PlayItem *pi = item->parent (); 0150 if (pi && pi->node) { 0151 pi->node->document ()->m_tree_version++; 0152 pi->node->closed (); 0153 } 0154 changed = true; 0155 } else if (item->node) { 0156 PlaylistRole *title = (PlaylistRole *) item->node->role (RolePlaylist); 0157 if (title && !ri->show_all_nodes && title->editable) { 0158 if (ntext.isEmpty ()) { 0159 ntext = item->node->mrl () 0160 ? item->node->mrl ()->src 0161 : title->caption (); 0162 changed = true; 0163 } 0164 if (title->caption () != ntext) { 0165 item->node->setNodeName (ntext); 0166 item->node->document ()->m_tree_version++; 0167 ntext = title->caption (); 0168 changed = true; 0169 } 0170 //} else { // restore damage .. 0171 // cannot update because of crashing, shouldn't get here anyhow 0172 //updateTree (ri, item->node, true); 0173 } 0174 } 0175 0176 if (changed) { 0177 item->title = ntext; 0178 Q_EMIT dataChanged (i, i); 0179 return true; 0180 } 0181 return false; 0182 } 0183 0184 Qt::ItemFlags PlayModel::flags (const QModelIndex &index) const 0185 { 0186 if (!index.isValid ()) 0187 return {}; 0188 0189 return static_cast<PlayItem*>(index.internalPointer())->item_flags; 0190 } 0191 0192 QVariant PlayModel::headerData (int, Qt::Orientation, int) const 0193 { 0194 return QVariant (); 0195 } 0196 0197 QModelIndex PlayModel::index (int row, int col, const QModelIndex &parent) const 0198 { 0199 if (!hasIndex(row, col, parent)) 0200 return QModelIndex(); 0201 0202 PlayItem *parent_item; 0203 0204 if (!parent.isValid()) 0205 parent_item = root_item; 0206 else 0207 parent_item = static_cast<PlayItem*>(parent.internalPointer()); 0208 0209 PlayItem *childItem = parent_item->child (row); 0210 if (childItem) 0211 return createIndex (row, col, childItem); 0212 else 0213 return QModelIndex(); 0214 } 0215 0216 QModelIndex PlayModel::indexFromItem (PlayItem *item) const 0217 { 0218 if (!item || item == root_item) 0219 return QModelIndex(); 0220 0221 return createIndex (item->row(), 0, item); 0222 } 0223 0224 PlayItem *PlayModel::itemFromIndex (const QModelIndex& index) const 0225 { 0226 if (!index.isValid ()) 0227 return nullptr; 0228 return static_cast <PlayItem*> (index.internalPointer ()); 0229 } 0230 0231 QModelIndex PlayModel::parent (const QModelIndex &index) const 0232 { 0233 if (!index.isValid()) 0234 return QModelIndex(); 0235 0236 PlayItem *childItem = static_cast <PlayItem*> (index.internalPointer ()); 0237 PlayItem *parent_item = childItem->parent (); 0238 0239 if (parent_item == root_item) 0240 return QModelIndex (); 0241 0242 return createIndex (parent_item->row(), 0, parent_item); 0243 } 0244 0245 bool PlayModel::hasChildren (const QModelIndex& parent) const 0246 { 0247 if (parent.column() > 0) 0248 return false; 0249 0250 if (!parent.isValid()) 0251 return root_item->childCount(); 0252 0253 PlayItem *pitem = static_cast<PlayItem*>(parent.internalPointer()); 0254 int count = pitem->childCount(); 0255 if (!count 0256 && pitem->parent_item == root_item 0257 && static_cast <TopPlayItem *> (pitem)->id > 0 0258 && !pitem->node->mrl()->resolved) { 0259 return true; 0260 } 0261 return count; 0262 } 0263 0264 int PlayModel::rowCount (const QModelIndex &parent) const 0265 { 0266 if (parent.column() > 0) 0267 return 0; 0268 0269 if (!parent.isValid()) 0270 return root_item->childCount(); 0271 0272 PlayItem *pitem = static_cast<PlayItem*>(parent.internalPointer()); 0273 int count = pitem->childCount(); 0274 if (!count && pitem->parent_item == root_item) { 0275 TopPlayItem *ritem = static_cast <TopPlayItem *> (pitem); 0276 if (ritem->id > 0 && !pitem->node->mrl()->resolved) { 0277 pitem->node->defer (); 0278 if (!pitem->node->mrl()->resolved) 0279 return 0; 0280 PlayItem *curitem = nullptr; 0281 ritem->model->populate (ritem->node, nullptr, ritem, nullptr, &curitem); 0282 count = ritem->childCount(); 0283 if (count) { 0284 ritem->model->beginInsertRows (parent, 0, count-1); 0285 ritem->model->endInsertRows (); 0286 } 0287 } 0288 } 0289 return count; 0290 } 0291 0292 int PlayModel::columnCount (const QModelIndex&) const 0293 { 0294 return 1; 0295 } 0296 0297 void dumpTree( PlayItem *p, const QString &indent ) { 0298 qCDebug(LOG_KMPLAYER_COMMON, "%s%s", qPrintable(indent),qPrintable(p->title)); 0299 for (int i=0; i < p->childCount(); i++) 0300 dumpTree(p->child(i), indent+" "); 0301 } 0302 0303 void TopPlayItem::add () 0304 { 0305 model->beginInsertRows (QModelIndex(), id, id); 0306 0307 parent_item = model->root_item; 0308 if (id >= model->root_item->childCount ()) 0309 model->root_item->child_items.append (this); 0310 else 0311 model->root_item->child_items.insert (id, this); 0312 0313 model->endInsertRows(); 0314 0315 if (id !=row()) 0316 qWarning("Invalid root tree"); 0317 } 0318 0319 void TopPlayItem ::remove () 0320 { 0321 model->beginRemoveRows (QModelIndex (), id, id); 0322 if (id < parent_item->childCount ()) 0323 parent_item->child_items.takeAt (id); 0324 else 0325 qWarning( "TopPlayItem::remove"); 0326 model->endRemoveRows(); 0327 } 0328 0329 PlayItem *PlayModel::populate (Node *e, Node *focus, 0330 TopPlayItem *root, PlayItem *pitem, 0331 PlayItem ** curitem) 0332 { 0333 root->have_dark_nodes |= !e->role (RolePlaylist); 0334 if (pitem && !root->show_all_nodes && !e->role (RolePlaylist)) { 0335 for (Node *c = e->firstChild (); c; c = c->nextSibling ()) 0336 populate (c, focus, root, pitem, curitem); 0337 return pitem; 0338 } 0339 PlayItem *item = root; 0340 if (pitem) { 0341 item = new PlayItem (e, pitem); 0342 pitem->appendChild (item); 0343 } 0344 item->item_flags |= root->itemFlags (); 0345 PlaylistRole *title = (PlaylistRole *) e->role (RolePlaylist); 0346 QString text (title ? title->caption () : ""); 0347 if (text.isEmpty ()) { 0348 text = id_node_text == e->id ? e->nodeValue () : e->nodeName (); 0349 if (e->isDocument ()) 0350 text = e->hasChildNodes () ? i18n ("unnamed") : i18n ("none"); 0351 } 0352 item->title = text; 0353 if (title && !root->show_all_nodes && title->editable) 0354 item->item_flags |= Qt::ItemIsEditable; 0355 if (focus == e) 0356 *curitem = item; 0357 //if (e->active ()) 0358 //scrollToItem (item); 0359 for (Node *c = e->firstChild (); c; c = c->nextSibling ()) 0360 populate (c, focus, root, item, curitem); 0361 if (e->isElementNode ()) { 0362 Attribute *a = static_cast <Element *> (e)->attributes ().first (); 0363 if (a) { 0364 root->have_dark_nodes = true; 0365 if (root->show_all_nodes) { 0366 PlayItem *as = new PlayItem (e, item); 0367 item->appendChild (as); 0368 as->title = i18n ("[attributes]"); 0369 for (; a; a = a->nextSibling ()) { 0370 PlayItem * ai = new PlayItem (a, as); 0371 as->appendChild (ai); 0372 //pitem->setFlags(root->itemFlags() &=~Qt::ItemIsDragEnabled); 0373 if (root->id > 0) 0374 ai->item_flags |= Qt::ItemIsEditable; 0375 ai->title = QString ("%1=%2").arg ( 0376 a->name ().toString ()).arg (a->value ()); 0377 } 0378 } 0379 } 0380 } 0381 //if (root->flags & PlayModel::AllowDrag) 0382 // item->setDragEnabled (true); 0383 return item; 0384 } 0385 0386 int PlayModel::addTree (NodePtr doc, const QString &source, const QString &icon, int flags) { 0387 TopPlayItem *ritem = new TopPlayItem(this, ++last_id, doc, flags); 0388 ritem->source = source; 0389 ritem->icon = KIconLoader::global ()->loadIcon (icon, KIconLoader::Small); 0390 PlayItem *curitem = nullptr; 0391 populate (doc, nullptr, ritem, nullptr, &curitem); 0392 ritem->add (); 0393 return last_id; 0394 } 0395 0396 void PlayModel::updateTree (int id, NodePtr root, NodePtr active, 0397 bool select, bool open) { 0398 // TODO, if root is same as rootitems->node and treeversion is the same 0399 // and show all nodes is unchanged then only update the cells 0400 int root_item_count = root_item->childCount (); 0401 TopPlayItem *ritem = nullptr; 0402 if (id == -1) { // wildcard id 0403 for (int i = 0; i < root_item_count; ++i) { 0404 ritem = static_cast<TopPlayItem*>(root_item->child (i)); 0405 for (NodePtr n = root; n; n = n->parentNode ()) 0406 if (n == ritem->node) { 0407 root = n; 0408 break; 0409 } 0410 if (root == ritem->node) { 0411 id = ritem->id; 0412 break; // found based on matching (ancestor) node 0413 } 0414 } 0415 } else if (id < root_item_count) { 0416 ritem = static_cast<TopPlayItem*>(root_item->child (id)); 0417 if (!root) 0418 root = ritem->node; 0419 } 0420 if (ritem) { 0421 ritem->node = root; 0422 bool need_timer = !tree_update; 0423 tree_update = new TreeUpdate (ritem, active, select, open, tree_update); 0424 if (need_timer) 0425 QTimer::singleShot (0, this, &PlayModel::updateTrees); 0426 } else 0427 qCDebug(LOG_KMPLAYER_COMMON) << "updateTree root item not found"; 0428 } 0429 0430 void PlayModel::updateTrees () { 0431 for (; tree_update; tree_update = tree_update->next) { 0432 Q_EMIT updating (indexFromItem (tree_update->root_item)); 0433 PlayItem *cur = updateTree (tree_update->root_item, tree_update->node); 0434 Q_EMIT updated (indexFromItem (tree_update->root_item), 0435 indexFromItem (cur), tree_update->select, tree_update->open); 0436 } 0437 } 0438 0439 PlayItem *PlayModel::updateTree (TopPlayItem *ritem, NodePtr active) { 0440 PlayItem *curitem = nullptr; 0441 0442 ritem->remove (); 0443 ritem->deleteChildren (); 0444 if (ritem->node) { 0445 if (!ritem->show_all_nodes) 0446 for (NodePtr n = active; n; n = n->parentNode ()) { 0447 active = n; 0448 if (n->role (RolePlaylist)) 0449 break; 0450 } 0451 populate (ritem->node, active, ritem, nullptr, &curitem); 0452 } 0453 ritem->add (); 0454 0455 return curitem; 0456 } 0457 0458 #include "moc_playmodel.cpp"