Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5 andreas 1
/*
386 andreas 2
 * Copyright (C) 2020 to 2023 by Andreas Theofilu <andreas@theosys.at>
5 andreas 3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
 
296 andreas 19
#include <functional>
20
#include <map>
21
 
5 andreas 22
#include <QTextObject>
23
#include <QLabel>
24
#include <QImage>
25
#include <QWidget>
41 andreas 26
#include <QPropertyAnimation>
279 andreas 27
#include <QListWidget>
264 andreas 28
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
21 andreas 29
#include <QtMultimedia/QMediaPlayer>
30
#include <QtMultimediaWidgets/QVideoWidget>
187 andreas 31
#else
32
#include <QTextLayout>
181 andreas 33
#endif
5 andreas 34
#include "tobject.h"
35
#include "terror.h"
285 andreas 36
#include "tqscrollarea.h"
391 andreas 37
#include "tqmarquee.h"
294 andreas 38
#include "tlock.h"
296 andreas 39
#include "tqtmain.h"
297 andreas 40
#include "tresources.h"
5 andreas 41
 
107 andreas 42
using std::string;
296 andreas 43
using std::map;
44
using std::pair;
107 andreas 45
 
5 andreas 46
TObject::TObject()
47
{
48
    DECL_TRACER("TObject::TObject()");
49
}
50
 
51
TObject::~TObject()
52
{
53
    DECL_TRACER("TObject::~TObject()");
54
 
89 andreas 55
    clear();
56
}
57
 
58
void TObject::clear(bool force)
59
{
60
    DECL_TRACER("TObject::clear()");
61
 
296 andreas 62
    if (mObjects.empty())
63
        return;
5 andreas 64
 
296 andreas 65
    std::map<ulong, OBJECT_t>::iterator iter;
66
 
67
    for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
5 andreas 68
    {
89 andreas 69
        if (!force)
296 andreas 70
            dropContent(&iter->second);
5 andreas 71
    }
89 andreas 72
 
296 andreas 73
    mObjects.clear();
5 andreas 74
}
75
 
198 andreas 76
void TObject::dropContent(OBJECT_t* obj, bool lock)
14 andreas 77
{
198 andreas 78
    DECL_TRACER("TObject::dropContent(OBJECT_t* obj, bool lock)");
14 andreas 79
 
349 andreas 80
    if (!obj)
81
        return;
82
 
198 andreas 83
    if (lock)
294 andreas 84
        TLOCKER(mutex_obj);
107 andreas 85
 
89 andreas 86
    try
14 andreas 87
    {
89 andreas 88
        switch (obj->type)
89
        {
90
            case OBJ_TEXT:
91
            case OBJ_INPUT:
188 andreas 92
                if (obj->object.plaintext)
190 andreas 93
                {
94
                    obj->object.plaintext->close();
188 andreas 95
                    obj->object.plaintext = nullptr;
190 andreas 96
                }
198 andreas 97
 
89 andreas 98
                obj->wid = 0;
271 andreas 99
                obj->invalid = true;
89 andreas 100
            break;
51 andreas 101
 
89 andreas 102
            case OBJ_BUTTON:
103
                if (obj->object.label)
104
                    obj->object.label = nullptr;
271 andreas 105
 
106
                obj->invalid = true;
89 andreas 107
            break;
108
 
391 andreas 109
            case OBJ_MARQUEE:
110
                if (obj->object.marquee)
111
                    obj->object.marquee = nullptr;
112
 
113
                obj->invalid = true;
114
            break;
115
 
185 andreas 116
            // This are the parent widgets (windows) and must be deleted.
117
            // If this widgets are deleted, Qt deletes their children.
89 andreas 118
            case OBJ_PAGE:
119
            case OBJ_SUBPAGE:
271 andreas 120
                obj->invalid = true;
121
 
89 andreas 122
                if (obj->object.widget)
123
                {
271 andreas 124
                    if (obj->type == OBJ_SUBPAGE)
125
                    {
264 andreas 126
                        obj->object.widget->close();        // This deletes all childs and the widget itself
271 andreas 127
                        obj->object.widget = nullptr;
128
                    }
129
                    else
130
                        obj->object.widget->hide();         // Don't delete a page because it is still stored in the stacked widget.
96 andreas 131
                }
198 andreas 132
            break;
14 andreas 133
 
279 andreas 134
            case OBJ_SUBVIEW:
135
                obj->invalid = true;
136
 
285 andreas 137
                if (obj->object.area)
279 andreas 138
                {
296 andreas 139
                    if (mMainWindow)
321 andreas 140
                    {
141
                        obj->connected = false;
296 andreas 142
                        mMainWindow->disconnectArea(obj->object.area);
321 andreas 143
                    }
296 andreas 144
 
285 andreas 145
                    delete obj->object.area;
146
                    obj->object.area = nullptr;
279 andreas 147
                }
148
            break;
149
 
89 andreas 150
            case OBJ_VIDEO:
151
                if (obj->object.vwidget)
152
                {
264 andreas 153
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
89 andreas 154
                    if (obj->player)
155
                        delete obj->player;
182 andreas 156
#endif
89 andreas 157
                    obj->object.vwidget = nullptr;
158
                    obj->player = nullptr;
159
                }
271 andreas 160
 
161
                obj->invalid = true;
200 andreas 162
            break;
21 andreas 163
 
200 andreas 164
            case OBJ_LIST:
165
                if (obj->object.list)
296 andreas 166
                {
167
                    if (mMainWindow)
168
                        mMainWindow->disconnectList(obj->object.list);
169
 
170
                    obj->object.list->close();
200 andreas 171
                    obj->object.list = nullptr;
296 andreas 172
                }
271 andreas 173
 
174
                obj->invalid = true;
200 andreas 175
            break;
176
 
89 andreas 177
            default:
271 andreas 178
                obj->invalid = true;
89 andreas 179
                break;
180
        }
14 andreas 181
    }
89 andreas 182
    catch (std::exception& e)
183
    {
184
        MSG_ERROR("Error freeing an object: " << e.what());
185
    }
14 andreas 186
}
187
 
386 andreas 188
void TObject::markDroped(ulong handle)
189
{
190
    DECL_TRACER("TObject::markDroped(ulong handle)");
191
 
192
    OBJECT_t *obj = findObject(handle);
193
 
194
    if (!obj)
195
        return;
196
 
197
    obj->remove = true;
198
}
199
 
296 andreas 200
bool TObject::addObject(OBJECT_t& obj)
5 andreas 201
{
296 andreas 202
    DECL_TRACER("TObject::addObject(OBJECT_t& obj)");
5 andreas 203
 
296 andreas 204
    if (obj.handle == 0 || obj.type == OBJ_NONE)
205
        return false;
5 andreas 206
 
349 andreas 207
    TLOCKER(mutex_obj);
208
 
209
    if (!mObjects.empty() && mObjects.find(obj.handle) != mObjects.end())
296 andreas 210
        return false;
5 andreas 211
 
296 andreas 212
    const auto [o, success] = mObjects.insert(pair<ulong, OBJECT_t>(obj.handle, obj));
213
    return success;
5 andreas 214
}
215
 
216
TObject::OBJECT_t *TObject::findObject(ulong handle)
217
{
218
    DECL_TRACER("TObject::findObject(ulong handle)");
219
 
349 andreas 220
    if (mObjects.empty())
221
        return nullptr;
222
 
296 andreas 223
    map<ulong, OBJECT_t>::iterator iter = mObjects.find(handle);
5 andreas 224
 
296 andreas 225
    if (iter != mObjects.end())
226
        return &iter->second;
5 andreas 227
 
228
    return nullptr;
229
}
230
 
349 andreas 231
TObject::OBJECT_t *TObject::findObject(WId id)
51 andreas 232
{
233
    DECL_TRACER("TObject::findObject(WId id)");
234
 
296 andreas 235
    if (mObjects.empty())
236
        return nullptr;
51 andreas 237
 
296 andreas 238
    map<ulong, OBJECT_t>::iterator iter;
239
 
240
    for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
51 andreas 241
    {
296 andreas 242
        if (iter->second.wid == id)
243
            return &iter->second;
51 andreas 244
    }
245
 
246
    return nullptr;
247
}
248
 
11 andreas 249
TObject::OBJECT_t *TObject::findFirstChild(ulong handle)
250
{
251
    DECL_TRACER("TObject::findFirstChild(ulong handle)");
252
 
349 andreas 253
    if (mObjects.empty())
254
        return nullptr;
255
 
296 andreas 256
    map<ulong, OBJECT_t>::iterator iter;
11 andreas 257
 
296 andreas 258
    for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
11 andreas 259
    {
296 andreas 260
        if (iter->first != (handle & 0xffff0000) && (iter->first & 0xffff0000) == (handle & 0xffff0000))
261
            return &iter->second;
11 andreas 262
    }
263
 
264
    return nullptr;
265
}
266
 
267
TObject::OBJECT_t *TObject::findNextChild(ulong handle)
268
{
269
    DECL_TRACER("TObject::findNextChild(ulong handle)");
270
 
349 andreas 271
    if (mObjects.empty())
272
        return nullptr;
273
 
296 andreas 274
    map<ulong, OBJECT_t>::iterator iter;
275
    bool next = true;
11 andreas 276
 
296 andreas 277
    for (iter = mObjects.find(handle); iter != mObjects.end(); ++iter)
11 andreas 278
    {
296 andreas 279
        if (next)
280
        {
281
            next = false;
282
            continue;
283
        }
11 andreas 284
 
296 andreas 285
        if ((iter->first & 0xffff0000) == (handle & 0xffff0000))
286
            return &iter->second;
11 andreas 287
    }
288
 
289
    return nullptr;
290
}
291
 
42 andreas 292
TObject::OBJECT_t * TObject::getMarkedRemove()
293
{
294
    DECL_TRACER("TObject::getMarkedRemove()");
51 andreas 295
 
349 andreas 296
    if (mObjects.empty())
297
        return nullptr;
298
 
296 andreas 299
    map<ulong, OBJECT_t>::iterator iter;
51 andreas 300
 
296 andreas 301
    for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
42 andreas 302
    {
296 andreas 303
        if (iter->second.remove)
304
            return &iter->second;
42 andreas 305
    }
51 andreas 306
 
42 andreas 307
    return nullptr;
308
}
309
 
310
TObject::OBJECT_t * TObject::getNextMarkedRemove(TObject::OBJECT_t* object)
311
{
312
    DECL_TRACER("TObject::getNextMarkedRemove(TObject::OBJECT_t* obj)");
51 andreas 313
 
349 andreas 314
    if (!object || mObjects.empty())
42 andreas 315
        return nullptr;
51 andreas 316
 
296 andreas 317
    map<ulong, OBJECT_t>::iterator iter;
318
    bool next = true;
51 andreas 319
 
296 andreas 320
    for (iter = mObjects.find(object->handle); iter != mObjects.end(); ++iter)
42 andreas 321
    {
296 andreas 322
        if (next)
323
        {
324
            next = false;
325
            continue;
326
        }
51 andreas 327
 
296 andreas 328
        if (iter->second.remove)
329
            return &iter->second;
42 andreas 330
    }
51 andreas 331
 
42 andreas 332
    return nullptr;
333
}
334
 
383 andreas 335
TObject::OBJECT_t *TObject::getFirstDirty()
336
{
337
    DECL_TRACER("TObject::getFirstDirty()");
338
 
339
    if (mObjects.empty())
340
        return nullptr;
341
 
342
    map<ulong, OBJECT_t>::iterator iter;
343
 
344
    for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
345
    {
346
        if (iter->second.dirty)
347
            return &iter->second;
348
    }
349
 
350
    return nullptr;
351
}
352
 
353
TObject::OBJECT_t *TObject::getNextDirty(OBJECT_t *obj)
354
{
355
    DECL_TRACER("TObject::getNextDirty(OBJECT_t *obj)");
356
 
357
    if (!obj || mObjects.empty())
358
        return nullptr;
359
 
360
    map<ulong, OBJECT_t>::iterator iter;
361
    bool next = true;
362
 
363
    for (iter = mObjects.find(obj->handle); iter != mObjects.end(); ++iter)
364
    {
365
        if (next)
366
        {
367
            next = false;
368
            continue;
369
        }
370
 
371
        if (iter->second.dirty)
372
            return &iter->second;
373
    }
374
 
375
    return nullptr;
376
}
142 andreas 377
TObject::OBJECT_t *TObject::findFirstWindow()
378
{
379
    DECL_TRACER("TObject::getFirstWindow()");
380
 
349 andreas 381
    if (mObjects.empty())
382
        return nullptr;
383
 
296 andreas 384
    map<ulong, OBJECT_t>::iterator iter;
142 andreas 385
 
296 andreas 386
    for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
142 andreas 387
    {
296 andreas 388
        if (iter->second.type == OBJ_SUBPAGE)
389
            return &iter->second;
142 andreas 390
    }
391
 
392
    return nullptr;
393
}
394
 
395
TObject::OBJECT_t *TObject::findNextWindow(TObject::OBJECT_t *obj)
396
{
397
    DECL_TRACER("TObject::findNextWindow()");
398
 
349 andreas 399
    if (!obj || mObjects.empty())
142 andreas 400
        return nullptr;
401
 
296 andreas 402
    map<ulong, OBJECT_t>::iterator iter;
403
    bool next = true;
142 andreas 404
 
296 andreas 405
    for (iter = mObjects.find(obj->handle); iter != mObjects.end(); ++iter)
142 andreas 406
    {
296 andreas 407
        if (next)
408
        {
409
            next = false;
410
            continue;
411
        }
142 andreas 412
 
296 andreas 413
        if (iter->second.type == OBJ_SUBPAGE)
414
            return &iter->second;
142 andreas 415
    }
416
 
417
    return nullptr;
418
}
419
 
198 andreas 420
void TObject::removeObject(ulong handle, bool drop)
5 andreas 421
{
198 andreas 422
    DECL_TRACER("TObject::removeObject(ulong handle, bool drop)");
5 andreas 423
 
296 andreas 424
    if (!handle || mObjects.empty())
215 andreas 425
        return;
426
 
296 andreas 427
    TLOCKER(mutex_obj);
428
    map<ulong, OBJECT_t>::iterator iter = mObjects.find(handle);
5 andreas 429
 
296 andreas 430
    if (iter != mObjects.end())
5 andreas 431
    {
296 andreas 432
        if (drop)
433
            dropContent(&iter->second, false);
198 andreas 434
 
296 andreas 435
        mObjects.erase(iter);
5 andreas 436
    }
437
}
438
 
198 andreas 439
void TObject::removeAllChilds(ulong handle, bool drop)
11 andreas 440
{
198 andreas 441
    DECL_TRACER("TObject::removeAllChilds(ulong handle, bool drop)");
11 andreas 442
 
296 andreas 443
    if (!handle || mObjects.empty())
215 andreas 444
        return;
445
 
294 andreas 446
    TLOCKER(mutex_obj);
296 andreas 447
    map<ulong, OBJECT_t>::iterator iter;
448
    bool repeat = false;
11 andreas 449
 
296 andreas 450
    do
11 andreas 451
    {
296 andreas 452
        repeat = false;
453
 
454
        for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
14 andreas 455
        {
296 andreas 456
            if ((iter->first & 0xffff0000) == (handle & 0xffff0000) && iter->first != (handle & 0xffff0000))
14 andreas 457
            {
198 andreas 458
                if (drop)
296 andreas 459
                    dropContent(&iter->second, false);
198 andreas 460
 
296 andreas 461
                mObjects.erase(iter);
462
                repeat = true;
463
                break;
14 andreas 464
            }
465
        }
11 andreas 466
    }
296 andreas 467
    while (repeat);
11 andreas 468
}
14 andreas 469
 
107 andreas 470
void TObject::cleanMarked()
14 andreas 471
{
107 andreas 472
    DECL_TRACER("TObject::cleanMarked()");
473
 
349 andreas 474
    if (mObjects.empty())
475
        return;
476
 
296 andreas 477
    TLOCKER(mutex_obj);
478
    map<ulong, OBJECT_t>::iterator iter;
479
    bool repeat = false;
107 andreas 480
 
296 andreas 481
    do
107 andreas 482
    {
296 andreas 483
        repeat = false;
484
 
485
        for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
107 andreas 486
        {
296 andreas 487
            if (iter->second.remove && (!iter->second.animation || iter->second.animation->state() != QAbstractAnimation::Running))
198 andreas 488
            {
296 andreas 489
                if (iter->second.type == OBJ_SUBPAGE && iter->second.object.widget)
490
                {
491
                    iter->second.object.widget->close();
492
                    iter->second.object.widget = nullptr;
493
                }
107 andreas 494
 
296 andreas 495
                mObjects.erase(iter);
496
                repeat = true;
497
                break;
107 andreas 498
            }
499
        }
500
    }
296 andreas 501
    while (repeat);
107 andreas 502
}
503
 
217 andreas 504
void TObject::invalidateAllObjects()
505
{
506
    DECL_TRACER("TObject::invalidateAllObjects()");
507
 
349 andreas 508
    if (mObjects.empty())
509
        return;
510
 
296 andreas 511
    TLOCKER(mutex_obj);
512
    map<ulong, OBJECT_t>::iterator iter;
217 andreas 513
 
296 andreas 514
    for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
217 andreas 515
    {
296 andreas 516
        iter->second.remove = false;
517
        iter->second.invalid = true;
518
    }
519
}
217 andreas 520
 
296 andreas 521
void TObject::invalidateObject(ulong handle)
522
{
523
    DECL_TRACER("TObject::invalidateObject(ulong handle)");
524
 
349 andreas 525
    if (mObjects.empty())
526
        return;
527
 
296 andreas 528
    TLOCKER(mutex_obj);
529
    map<ulong, OBJECT_t>::iterator iter = mObjects.find(handle);
530
 
531
    if (iter != mObjects.end())
532
    {
533
        iter->second.remove = false;
534
        iter->second.invalid = true;
217 andreas 535
    }
536
}
537
 
538
void TObject::invalidateAllSubObjects(ulong handle)
539
{
297 andreas 540
    DECL_TRACER("TObject::invalidateAllSubObjects(ulong handle)");
217 andreas 541
 
297 andreas 542
    if (mObjects.empty())
543
        return;
544
 
350 andreas 545
    TLOCKER(mutex_obj);
546
 
296 andreas 547
    map<ulong, OBJECT_t>::iterator iter;
297 andreas 548
    bool first = true;
217 andreas 549
 
297 andreas 550
    for (iter = mObjects.find(handle); iter != mObjects.end(); ++iter)
217 andreas 551
    {
297 andreas 552
        if (first)
217 andreas 553
        {
297 andreas 554
            first = false;
555
            continue;
556
        }
557
 
558
        if ((iter->first & 0xffff0000) == handle)
559
        {
560
            MSG_DEBUG("Invalidating object " << handleToString(iter->first) << " of type " << objectToString(iter->second.type));
296 andreas 561
            iter->second.remove = false;
562
            iter->second.invalid = true;
297 andreas 563
 
321 andreas 564
            if (iter->second.type == OBJ_SUBVIEW && iter->second.object.area && mMainWindow && iter->second.connected)
565
            {
566
                iter->second.connected = false;
297 andreas 567
                mMainWindow->disconnectArea(iter->second.object.area);
321 andreas 568
            }
569
            else if (iter->second.type == OBJ_LIST && iter->second.object.list && mMainWindow && iter->second.connected)
570
            {
571
                iter->second.connected = false;
297 andreas 572
                mMainWindow->disconnectList(iter->second.object.list);
321 andreas 573
            }
217 andreas 574
        }
296 andreas 575
    }
576
}
217 andreas 577
 
296 andreas 578
bool TObject::enableObject(ulong handle)
579
{
580
    DECL_TRACER("TObject::enableObject(ulong handle)");
581
 
349 andreas 582
    if (mObjects.empty())
583
        return false;
584
 
296 andreas 585
    map<ulong, OBJECT_t>::iterator iter = mObjects.find(handle);
586
 
587
    if (iter != mObjects.end())
588
    {
589
        if (!iter->second.object.widget)
590
        {
591
            iter->second.remove = true;
297 andreas 592
            MSG_ERROR("Object " << handleToString(iter->first) << " of type " << objectToString(iter->second.type) << " has no QObject!");
296 andreas 593
            return false;
594
        }
595
 
323 andreas 596
        TLOCKER(mutex_obj);
296 andreas 597
        iter->second.remove = false;
598
        iter->second.invalid = false;
599
 
321 andreas 600
        if (iter->second.type == OBJ_SUBVIEW && iter->second.object.area && mMainWindow && !iter->second.connected)
601
        {
297 andreas 602
            mMainWindow->reconnectArea(iter->second.object.area);
321 andreas 603
            iter->second.connected = true;
604
        }
605
        else if (iter->second.type == OBJ_LIST && iter->second.object.list && mMainWindow && !iter->second.connected)
606
        {
297 andreas 607
            mMainWindow->reconnectList(iter->second.object.list);
321 andreas 608
            iter->second.connected = true;
609
        }
297 andreas 610
 
296 andreas 611
        return true;                         // We can savely return here because a handle is unique
217 andreas 612
    }
613
 
296 andreas 614
    return false;
217 andreas 615
}
616
 
296 andreas 617
bool TObject::enableAllSubObjects(ulong handle)
618
{
619
    DECL_TRACER("::enableAllSubObjects(ulong handle)");
620
 
349 andreas 621
    if (mObjects.empty())
622
        return false;
623
 
296 andreas 624
    TLOCKER(mutex_obj);
625
    map<ulong, OBJECT_t>::iterator iter;
626
    bool ret = true;
627
 
628
    for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
629
    {
630
        if (iter->first != handle && (iter->first & 0xffff0000) == handle)
631
        {
632
            if (!iter->second.object.widget)
633
            {
634
                iter->second.remove = true;
297 andreas 635
                MSG_ERROR("Object " << handleToString(iter->first) << " of type " << objectToString(iter->second.type) << " has no QObject!");
296 andreas 636
                ret = false;
637
            }
638
            else
639
            {
640
                iter->second.remove = false;
641
                iter->second.invalid = false;
297 andreas 642
 
321 andreas 643
                if (iter->second.type == OBJ_SUBVIEW && iter->second.object.area && mMainWindow && !iter->second.connected)
644
                {
297 andreas 645
                    mMainWindow->reconnectArea(iter->second.object.area);
321 andreas 646
                    iter->second.connected = true;
647
                }
648
                else if (iter->second.type == OBJ_LIST && iter->second.object.list && mMainWindow && !iter->second.connected)
649
                {
297 andreas 650
                    mMainWindow->reconnectList(iter->second.object.list);
321 andreas 651
                    iter->second.connected = true;
652
                }
296 andreas 653
            }
654
        }
655
    }
656
 
657
    return ret;
658
}
659
 
107 andreas 660
string TObject::objectToString(TObject::OBJECT_TYPE o)
661
{
14 andreas 662
    switch(o)
663
    {
664
        case OBJ_BUTTON:  return "BUTTON"; break;
391 andreas 665
        case OBJ_MARQUEE: return "MARQUEE"; break;
14 andreas 666
        case OBJ_INPUT:   return "INPUT"; break;
667
        case OBJ_NONE:    return "undefined"; break;
668
        case OBJ_PAGE:    return "PAGE"; break;
669
        case OBJ_SUBPAGE: return "SUBPAGE"; break;
670
        case OBJ_TEXT:    return "TEXT"; break;
21 andreas 671
        case OBJ_VIDEO:   return "VIDEO"; break;
200 andreas 672
        case OBJ_LIST:    return "LIST"; break;
279 andreas 673
        case OBJ_SUBVIEW: return "SUBVIEW"; break;
14 andreas 674
    }
78 andreas 675
 
107 andreas 676
    return string();   // Should not happen but is needed to satisfy the compiler.
14 andreas 677
}