Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

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