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