| Directory: | ./ |
|---|---|
| File: | src/MessageModelUnion.cpp |
| Date: | 2025-11-14 14:56:08 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 106 | 168 | 63.1% |
| Branches: | 79 | 267 | 29.6% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * Copyright (C) 2009 - 2025 Florian Pose <fp@igh.de> | ||
| 4 | * | ||
| 5 | * This file is part of the QtPdCom library. | ||
| 6 | * | ||
| 7 | * The QtPdCom library is free software: you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Lesser General Public License as published by | ||
| 9 | * the Free Software Foundation, either version 3 of the License, or (at your | ||
| 10 | * option) any later version. | ||
| 11 | * | ||
| 12 | * The QtPdCom library is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | ||
| 15 | * License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public License | ||
| 18 | * along with the QtPdCom Library. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | * | ||
| 20 | ****************************************************************************/ | ||
| 21 | |||
| 22 | #include "MessageModelUnion.h" | ||
| 23 | using QtPdCom::MessageModelUnion; | ||
| 24 | |||
| 25 | #include "MessageModel.h" | ||
| 26 | |||
| 27 | #include <QAbstractProxyModel> | ||
| 28 | |||
| 29 | #if PD_DEBUG_MESSAGE_MODEL | ||
| 30 | #include <QDebug> | ||
| 31 | #endif | ||
| 32 | |||
| 33 | /***************************************************************************** | ||
| 34 | * MessageModelUnion::Impl | ||
| 35 | ****************************************************************************/ | ||
| 36 | |||
| 37 | 2 | struct MessageModelUnion::Impl | |
| 38 | { | ||
| 39 | Impl() = delete; | ||
| 40 | 2 | Impl(MessageModelUnion *parent): | |
| 41 | 2 | parentModel {parent} | |
| 42 | 2 | {} | |
| 43 | |||
| 44 | MessageModelUnion *const parentModel; | ||
| 45 | |||
| 46 |
1/2✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | struct SourceModel |
| 47 | { | ||
| 48 | 6 | ~SourceModel() { QObject::disconnect(connection); } | |
| 49 | |||
| 50 | QAbstractItemModel *model; | ||
| 51 | QString name; | ||
| 52 | const QtPdCom::Message *announcedMessage; | ||
| 53 | QMetaObject::Connection connection; | ||
| 54 | }; | ||
| 55 | QList<SourceModel> sourceModels; | ||
| 56 | |||
| 57 | struct SourceEntry | ||
| 58 | { | ||
| 59 | SourceModel *sourceModel; | ||
| 60 | int row; // original row in source model | ||
| 61 | }; | ||
| 62 | QVector<SourceEntry> mergedRows; | ||
| 63 | |||
| 64 | enum { SortColumn = 1 }; | ||
| 65 | |||
| 66 | 13 | void rebuildMergedRows() | |
| 67 | { | ||
| 68 | 13 | parentModel->beginResetModel(); | |
| 69 | 13 | mergedRows.clear(); | |
| 70 | |||
| 71 |
5/8✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 16 times.
✓ Branch 10 taken 13 times.
✓ Branch 12 taken 16 times.
✗ Branch 13 not taken.
|
29 | for (auto &sourceModel : sourceModels) { |
| 72 |
1/2✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
|
16 | int rows = sourceModel.model->rowCount(); |
| 73 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 16 times.
|
21 | for (int row = 0; row < rows; ++row) { |
| 74 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | mergedRows.append({&sourceModel, row}); |
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | 13 | std::sort( | |
| 79 | mergedRows.begin(), | ||
| 80 | mergedRows.end(), | ||
| 81 | 2 | [this](const SourceEntry &a, const SourceEntry &b) { | |
| 82 | 2 | QVariant va = a.sourceModel->model->data( | |
| 83 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
8 | a.sourceModel->model->index( |
| 84 | 2 | a.row, | |
| 85 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
12 | SortColumn)); |
| 86 | 2 | QVariant vb = b.sourceModel->model->data( | |
| 87 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
8 | b.sourceModel->model->index( |
| 88 | 2 | b.row, | |
| 89 |
1/2✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
12 | SortColumn)); |
| 90 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
4 | return vb.toString() < va.toString(); |
| 91 | }); | ||
| 92 | |||
| 93 | #if PD_DEBUG_MESSAGE_MODEL | ||
| 94 |
4/8✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 13 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 13 times.
✗ Branch 14 not taken.
|
26 | qDebug() << __func__ << "(): Now " << mergedRows.size() |
| 95 |
1/2✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
|
26 | << " rows."; |
| 96 | #endif | ||
| 97 | 13 | parentModel->endResetModel(); | |
| 98 | 13 | } | |
| 99 | |||
| 100 | 6 | void currentMessage( | |
| 101 | SourceModel *sourceModel, | ||
| 102 | const QtPdCom::Message *message) | ||
| 103 | { | ||
| 104 | #if PD_DEBUG_MESSAGE_MODEL | ||
| 105 |
4/8✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 6 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 6 times.
✗ Branch 17 not taken.
|
6 | qDebug() << __func__ << sourceModel << message; |
| 106 | #endif | ||
| 107 | 6 | sourceModel->announcedMessage = message; | |
| 108 | 6 | updateCurrentMessage(); | |
| 109 | 6 | } | |
| 110 | |||
| 111 | 6 | void updateCurrentMessage() | |
| 112 | { | ||
| 113 | 6 | const QtPdCom::Message *candidate {nullptr}; | |
| 114 |
5/8✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 10 times.
✓ Branch 10 taken 6 times.
✓ Branch 12 taken 10 times.
✗ Branch 13 not taken.
|
16 | for (auto &sourceModel : sourceModels) { |
| 115 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | if (sourceModel.announcedMessage) { |
| 116 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
|
5 | if (not candidate |
| 117 |
4/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
|
6 | or sourceModel.announcedMessage->getType() |
| 118 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | > candidate->getType()) { |
| 119 | 4 | candidate = sourceModel.announcedMessage; | |
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
| 123 | #if PD_DEBUG_MESSAGE_MODEL | ||
| 124 |
3/6✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 6 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 6 times.
✗ Branch 14 not taken.
|
6 | qDebug() << __func__ << candidate; |
| 125 | #endif | ||
| 126 | 6 | emit parentModel->currentMessage(candidate); | |
| 127 | 6 | } | |
| 128 | }; | ||
| 129 | |||
| 130 | /***************************************************************************** | ||
| 131 | * MessageModelUnion | ||
| 132 | ****************************************************************************/ | ||
| 133 | |||
| 134 | /** Constructor. | ||
| 135 | */ | ||
| 136 | 2 | MessageModelUnion::MessageModelUnion(QObject *parent): | |
| 137 | QAbstractTableModel(parent), | ||
| 138 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | impl(std::unique_ptr<Impl>(new MessageModelUnion::Impl(this))) |
| 139 | 2 | {} | |
| 140 | |||
| 141 | /****************************************************************************/ | ||
| 142 | |||
| 143 | /** Destructor. | ||
| 144 | */ | ||
| 145 | 6 | MessageModelUnion::~MessageModelUnion() | |
| 146 | { | ||
| 147 | 2 | clearSourceModels(); | |
| 148 | 4 | } | |
| 149 | |||
| 150 | /****************************************************************************/ | ||
| 151 | |||
| 152 | 3 | void MessageModelUnion::addSourceModel( | |
| 153 | QAbstractItemModel *model, | ||
| 154 | QString sourceName) | ||
| 155 | { | ||
| 156 |
1/2✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
3 | impl->sourceModels.push_back( |
| 157 | {model, | ||
| 158 | sourceName, | ||
| 159 | nullptr, // announced message | ||
| 160 | QMetaObject::Connection()}); | ||
| 161 | 3 | auto *sourceModel = &impl->sourceModels.last(); | |
| 162 | |||
| 163 | 6 | connect(model, &QAbstractTableModel::rowsInserted, [this]() { | |
| 164 | 3 | impl->rebuildMergedRows(); | |
| 165 | 3 | }); | |
| 166 | 3 | connect(model, &QAbstractTableModel::rowsRemoved, [this]() { | |
| 167 | ✗ | impl->rebuildMergedRows(); | |
| 168 | ✗ | }); | |
| 169 | 3 | connect(model, &QAbstractTableModel::dataChanged, [this]() { | |
| 170 | ✗ | impl->rebuildMergedRows(); | |
| 171 | ✗ | }); | |
| 172 | 3 | connect(model, &QAbstractTableModel::layoutChanged, [this]() { | |
| 173 | ✗ | impl->rebuildMergedRows(); | |
| 174 | ✗ | }); | |
| 175 | 10 | connect(model, &QAbstractTableModel::modelReset, [this]() { | |
| 176 | 7 | impl->rebuildMergedRows(); | |
| 177 | 7 | }); | |
| 178 | |||
| 179 | // find a QtPdCom::MessageModel after a chain of QAbstractProxyModels | ||
| 180 | 3 | QtPdCom::MessageModel *messageModel {nullptr}; | |
| 181 | while (true) { | ||
| 182 | 3 | auto *proxy {qobject_cast<QAbstractProxyModel *>(model)}; | |
| 183 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (not proxy) { |
| 184 | 3 | messageModel = qobject_cast<QtPdCom::MessageModel *>(model); | |
| 185 | 3 | break; | |
| 186 | } | ||
| 187 | ✗ | model = proxy->sourceModel(); | |
| 188 | } | ||
| 189 | |||
| 190 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (messageModel) { |
| 191 | 6 | sourceModel->connection = | |
| 192 | 6 | connect(messageModel, | |
| 193 | &MessageModel::currentMessage, | ||
| 194 | 12 | [this, sourceModel](const QtPdCom::Message *message) { | |
| 195 | 12 | impl->currentMessage(sourceModel, message); | |
| 196 | 9 | }); | |
| 197 | } | ||
| 198 | |||
| 199 | 3 | impl->rebuildMergedRows(); | |
| 200 | 3 | } | |
| 201 | |||
| 202 | /****************************************************************************/ | ||
| 203 | |||
| 204 | ✗ | void MessageModelUnion::removeSourceModel(QAbstractItemModel *model) | |
| 205 | { | ||
| 206 | ✗ | auto it = std::remove_if( | |
| 207 | ✗ | impl->sourceModels.begin(), | |
| 208 | ✗ | impl->sourceModels.end(), | |
| 209 | ✗ | [model](const Impl::SourceModel &s) { return s.model == model; }); | |
| 210 | ✗ | impl->sourceModels.erase(it, impl->sourceModels.end()); | |
| 211 | |||
| 212 | ✗ | impl->rebuildMergedRows(); | |
| 213 | } | ||
| 214 | |||
| 215 | /****************************************************************************/ | ||
| 216 | |||
| 217 | 3 | void MessageModelUnion::clearSourceModels() | |
| 218 | { | ||
| 219 | 3 | beginResetModel(); | |
| 220 | 3 | impl->sourceModels.clear(); | |
| 221 | 3 | endResetModel(); | |
| 222 | 3 | } | |
| 223 | |||
| 224 | /****************************************************************************/ | ||
| 225 | |||
| 226 | 22 | int MessageModelUnion::rowCount(const QModelIndex &) const | |
| 227 | { | ||
| 228 | 22 | return impl->mergedRows.count(); | |
| 229 | } | ||
| 230 | |||
| 231 | /****************************************************************************/ | ||
| 232 | |||
| 233 | 14 | int MessageModelUnion::columnCount(const QModelIndex &) const | |
| 234 | { | ||
| 235 | 14 | return 4; | |
| 236 | } | ||
| 237 | |||
| 238 | /****************************************************************************/ | ||
| 239 | |||
| 240 | 14 | QVariant MessageModelUnion::data(const QModelIndex &index, int role) const | |
| 241 | { | ||
| 242 | 14 | QVariant ret; | |
| 243 | |||
| 244 |
3/6✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 14 times.
✗ Branch 9 not taken.
|
14 | if (index.isValid() and index.row() < impl->mergedRows.size()) { |
| 245 |
1/2✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
|
14 | auto entry {impl->mergedRows[index.row()]}; |
| 246 | 14 | QModelIndex sourceIndex = | |
| 247 |
1/2✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
|
14 | entry.sourceModel->model->index(entry.row, index.column()); |
| 248 |
5/6✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 12 times.
✓ Branch 7 taken 2 times.
|
14 | if (index.column() >= TextColumn and index.column() < SourceColumn) { |
| 249 |
1/2✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
|
12 | ret = entry.sourceModel->model->data(sourceIndex, role); |
| 250 | } | ||
| 251 |
3/6✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
2 | else if (index.column() == SourceColumn and role == Qt::DisplayRole) { |
| 252 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | ret = entry.sourceModel->name; |
| 253 | } | ||
| 254 | } | ||
| 255 | |||
| 256 | #if PD_DEBUG_MESSAGE_MODEL | ||
| 257 |
5/10✓ Branch 8 taken 14 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 14 times.
✗ Branch 12 not taken.
✓ Branch 15 taken 14 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 14 times.
✗ Branch 19 not taken.
✓ Branch 22 taken 14 times.
✗ Branch 23 not taken.
|
14 | qDebug() << __func__ << index << role << ret; |
| 258 | #endif | ||
| 259 | 14 | return ret; | |
| 260 | } | ||
| 261 | |||
| 262 | /****************************************************************************/ | ||
| 263 | |||
| 264 | QVariant | ||
| 265 | ✗ | MessageModelUnion::headerData(int section, Qt::Orientation o, int role) const | |
| 266 | { | ||
| 267 | ✗ | if (role == Qt::DisplayRole && o == Qt::Horizontal) { | |
| 268 | ✗ | switch (section) { | |
| 269 | ✗ | case TextColumn: | |
| 270 | ✗ | return tr("Message"); | |
| 271 | |||
| 272 | ✗ | case TimeOccurredColumn: | |
| 273 | ✗ | return tr("Time"); | |
| 274 | |||
| 275 | ✗ | case TimeResetColumn: | |
| 276 | ✗ | return tr("Reset"); | |
| 277 | |||
| 278 | ✗ | case SourceColumn: | |
| 279 | ✗ | return tr("Source"); | |
| 280 | |||
| 281 | ✗ | default: | |
| 282 | ✗ | return QVariant(); | |
| 283 | } | ||
| 284 | } | ||
| 285 | else { | ||
| 286 | ✗ | return QVariant(); | |
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | /****************************************************************************/ | ||
| 291 | |||
| 292 | 4 | Qt::ItemFlags MessageModelUnion::flags(const QModelIndex &index) const | |
| 293 | { | ||
| 294 | 4 | Qt::ItemFlags ret; | |
| 295 | |||
| 296 |
3/6✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
|
4 | if (index.isValid() and index.row() < impl->mergedRows.size()) { |
| 297 |
1/2✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
4 | auto entry {impl->mergedRows[index.row()]}; |
| 298 | 4 | QModelIndex sourceIndex = | |
| 299 |
1/2✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | entry.sourceModel->model->index(entry.row, index.column()); |
| 300 |
3/6✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
|
4 | if (index.column() >= TextColumn and index.column() < SourceColumn) { |
| 301 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | ret = entry.sourceModel->model->flags(sourceIndex); |
| 302 | } | ||
| 303 | ✗ | else if (index.column() == SourceColumn) { | |
| 304 | ✗ | QModelIndex textIndex = | |
| 305 | ✗ | entry.sourceModel->model->index(entry.row, TextColumn); | |
| 306 | ✗ | ret = entry.sourceModel->model->flags(textIndex); | |
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | #if PD_DEBUG_MESSAGE_MODEL | ||
| 311 |
4/8✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 14 taken 4 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 4 times.
✗ Branch 18 not taken.
|
4 | qDebug() << __func__ << index << ret; |
| 312 | #endif | ||
| 313 | 4 | return ret; | |
| 314 | } | ||
| 315 | |||
| 316 | /****************************************************************************/ | ||
| 317 | |||
| 318 | ✗ | bool MessageModelUnion::canFetchMore(const QModelIndex &index) const | |
| 319 | { | ||
| 320 | #if PD_DEBUG_MESSAGE_MODEL | ||
| 321 | ✗ | qDebug() << __func__ << index; | |
| 322 | #endif | ||
| 323 | ✗ | if (not index.isValid()) { | |
| 324 | // root layer - return true if *any* model can fetch more rows | ||
| 325 | ✗ | for (auto &sourceModel : impl->sourceModels) { | |
| 326 | ✗ | if (sourceModel.model->canFetchMore(index)) { | |
| 327 | #if PD_DEBUG_MESSAGE_MODEL | ||
| 328 | ✗ | qDebug() << sourceModel.model << sourceModel.name << "yes"; | |
| 329 | #endif | ||
| 330 | ✗ | return true; | |
| 331 | } | ||
| 332 | } | ||
| 333 | #if PD_DEBUG_MESSAGE_MODEL | ||
| 334 | ✗ | qDebug() << "no"; | |
| 335 | #endif | ||
| 336 | ✗ | return false; | |
| 337 | } | ||
| 338 | ✗ | else if (index.row() < impl->mergedRows.size()) { | |
| 339 | ✗ | auto entry {impl->mergedRows[index.row()]}; | |
| 340 | ✗ | auto sourceIndex { | |
| 341 | ✗ | entry.sourceModel->model->index(entry.row, index.column())}; | |
| 342 | ✗ | auto canFetch {entry.sourceModel->model->canFetchMore(sourceIndex)}; | |
| 343 | #if PD_DEBUG_MESSAGE_MODEL | ||
| 344 | ✗ | qDebug() << "specific" << canFetch; | |
| 345 | #endif | ||
| 346 | ✗ | return canFetch; | |
| 347 | } | ||
| 348 | else { | ||
| 349 | #if PD_DEBUG_MESSAGE_MODEL | ||
| 350 | ✗ | qDebug() << "invalid"; | |
| 351 | #endif | ||
| 352 | ✗ | return false; | |
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 356 | /****************************************************************************/ | ||
| 357 | |||
| 358 | ✗ | void MessageModelUnion::fetchMore(const QModelIndex &index) | |
| 359 | { | ||
| 360 | #if PD_DEBUG_MESSAGE_MODEL | ||
| 361 | ✗ | qDebug() << __func__ << index; | |
| 362 | #endif | ||
| 363 | ✗ | if (not index.isValid()) { | |
| 364 | // root layer - pass on to *any* model that can fetch more rows | ||
| 365 | ✗ | for (auto &sourceModel : impl->sourceModels) { | |
| 366 | ✗ | if (sourceModel.model->canFetchMore(index)) { | |
| 367 | #if PD_DEBUG_MESSAGE_MODEL | ||
| 368 | ✗ | qDebug() << __func__ << sourceModel.model << sourceModel.name; | |
| 369 | #endif | ||
| 370 | ✗ | sourceModel.model->fetchMore(index); | |
| 371 | } | ||
| 372 | } | ||
| 373 | } | ||
| 374 | ✗ | else if (index.row() < impl->mergedRows.size()) { | |
| 375 | ✗ | auto entry {impl->mergedRows[index.row()]}; | |
| 376 | ✗ | auto sourceIndex { | |
| 377 | ✗ | entry.sourceModel->model->index(entry.row, index.column())}; | |
| 378 | ✗ | entry.sourceModel->model->fetchMore(sourceIndex); | |
| 379 | } | ||
| 380 | } | ||
| 381 | |||
| 382 | /****************************************************************************/ | ||
| 383 |