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
 
142 andreas 315
TObject::OBJECT_t *TObject::findFirstWindow()
316
{
317
    DECL_TRACER("TObject::getFirstWindow()");
318
 
349 andreas 319
    if (mObjects.empty())
320
        return nullptr;
321
 
296 andreas 322
    map<ulong, OBJECT_t>::iterator iter;
142 andreas 323
 
296 andreas 324
    for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
142 andreas 325
    {
296 andreas 326
        if (iter->second.type == OBJ_SUBPAGE)
327
            return &iter->second;
142 andreas 328
    }
329
 
330
    return nullptr;
331
}
332
 
333
TObject::OBJECT_t *TObject::findNextWindow(TObject::OBJECT_t *obj)
334
{
335
    DECL_TRACER("TObject::findNextWindow()");
336
 
349 andreas 337
    if (!obj || mObjects.empty())
142 andreas 338
        return nullptr;
339
 
296 andreas 340
    map<ulong, OBJECT_t>::iterator iter;
341
    bool next = true;
142 andreas 342
 
296 andreas 343
    for (iter = mObjects.find(obj->handle); iter != mObjects.end(); ++iter)
142 andreas 344
    {
296 andreas 345
        if (next)
346
        {
347
            next = false;
348
            continue;
349
        }
142 andreas 350
 
296 andreas 351
        if (iter->second.type == OBJ_SUBPAGE)
352
            return &iter->second;
142 andreas 353
    }
354
 
355
    return nullptr;
356
}
357
 
198 andreas 358
void TObject::removeObject(ulong handle, bool drop)
5 andreas 359
{
198 andreas 360
    DECL_TRACER("TObject::removeObject(ulong handle, bool drop)");
5 andreas 361
 
296 andreas 362
    if (!handle || mObjects.empty())
215 andreas 363
        return;
364
 
296 andreas 365
    TLOCKER(mutex_obj);
366
    map<ulong, OBJECT_t>::iterator iter = mObjects.find(handle);
5 andreas 367
 
296 andreas 368
    if (iter != mObjects.end())
5 andreas 369
    {
296 andreas 370
        if (drop)
371
            dropContent(&iter->second, false);
198 andreas 372
 
296 andreas 373
        mObjects.erase(iter);
5 andreas 374
    }
375
}
376
 
198 andreas 377
void TObject::removeAllChilds(ulong handle, bool drop)
11 andreas 378
{
198 andreas 379
    DECL_TRACER("TObject::removeAllChilds(ulong handle, bool drop)");
11 andreas 380
 
296 andreas 381
    if (!handle || mObjects.empty())
215 andreas 382
        return;
383
 
294 andreas 384
    TLOCKER(mutex_obj);
296 andreas 385
    map<ulong, OBJECT_t>::iterator iter;
386
    bool repeat = false;
11 andreas 387
 
296 andreas 388
    do
11 andreas 389
    {
296 andreas 390
        repeat = false;
391
 
392
        for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
14 andreas 393
        {
296 andreas 394
            if ((iter->first & 0xffff0000) == (handle & 0xffff0000) && iter->first != (handle & 0xffff0000))
14 andreas 395
            {
198 andreas 396
                if (drop)
296 andreas 397
                    dropContent(&iter->second, false);
198 andreas 398
 
296 andreas 399
                mObjects.erase(iter);
400
                repeat = true;
401
                break;
14 andreas 402
            }
403
        }
11 andreas 404
    }
296 andreas 405
    while (repeat);
11 andreas 406
}
14 andreas 407
 
107 andreas 408
void TObject::cleanMarked()
14 andreas 409
{
107 andreas 410
    DECL_TRACER("TObject::cleanMarked()");
411
 
349 andreas 412
    if (mObjects.empty())
413
        return;
414
 
296 andreas 415
    TLOCKER(mutex_obj);
416
    map<ulong, OBJECT_t>::iterator iter;
417
    bool repeat = false;
107 andreas 418
 
296 andreas 419
    do
107 andreas 420
    {
296 andreas 421
        repeat = false;
422
 
423
        for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
107 andreas 424
        {
296 andreas 425
            if (iter->second.remove && (!iter->second.animation || iter->second.animation->state() != QAbstractAnimation::Running))
198 andreas 426
            {
296 andreas 427
                if (iter->second.type == OBJ_SUBPAGE && iter->second.object.widget)
428
                {
429
                    iter->second.object.widget->close();
430
                    iter->second.object.widget = nullptr;
431
                }
107 andreas 432
 
296 andreas 433
                mObjects.erase(iter);
434
                repeat = true;
435
                break;
107 andreas 436
            }
437
        }
438
    }
296 andreas 439
    while (repeat);
107 andreas 440
}
441
 
217 andreas 442
void TObject::invalidateAllObjects()
443
{
444
    DECL_TRACER("TObject::invalidateAllObjects()");
445
 
349 andreas 446
    if (mObjects.empty())
447
        return;
448
 
296 andreas 449
    TLOCKER(mutex_obj);
450
    map<ulong, OBJECT_t>::iterator iter;
217 andreas 451
 
296 andreas 452
    for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
217 andreas 453
    {
296 andreas 454
        iter->second.remove = false;
455
        iter->second.invalid = true;
456
    }
457
}
217 andreas 458
 
296 andreas 459
void TObject::invalidateObject(ulong handle)
460
{
461
    DECL_TRACER("TObject::invalidateObject(ulong handle)");
462
 
349 andreas 463
    if (mObjects.empty())
464
        return;
465
 
296 andreas 466
    TLOCKER(mutex_obj);
467
    map<ulong, OBJECT_t>::iterator iter = mObjects.find(handle);
468
 
469
    if (iter != mObjects.end())
470
    {
471
        iter->second.remove = false;
472
        iter->second.invalid = true;
217 andreas 473
    }
474
}
475
 
476
void TObject::invalidateAllSubObjects(ulong handle)
477
{
297 andreas 478
    DECL_TRACER("TObject::invalidateAllSubObjects(ulong handle)");
217 andreas 479
 
297 andreas 480
    if (mObjects.empty())
481
        return;
482
 
350 andreas 483
    TLOCKER(mutex_obj);
484
 
296 andreas 485
    map<ulong, OBJECT_t>::iterator iter;
297 andreas 486
    bool first = true;
217 andreas 487
 
297 andreas 488
    for (iter = mObjects.find(handle); iter != mObjects.end(); ++iter)
217 andreas 489
    {
297 andreas 490
        if (first)
217 andreas 491
        {
297 andreas 492
            first = false;
493
            continue;
494
        }
495
 
496
        if ((iter->first & 0xffff0000) == handle)
497
        {
498
            MSG_DEBUG("Invalidating object " << handleToString(iter->first) << " of type " << objectToString(iter->second.type));
296 andreas 499
            iter->second.remove = false;
500
            iter->second.invalid = true;
297 andreas 501
 
321 andreas 502
            if (iter->second.type == OBJ_SUBVIEW && iter->second.object.area && mMainWindow && iter->second.connected)
503
            {
504
                iter->second.connected = false;
297 andreas 505
                mMainWindow->disconnectArea(iter->second.object.area);
321 andreas 506
            }
507
            else if (iter->second.type == OBJ_LIST && iter->second.object.list && mMainWindow && iter->second.connected)
508
            {
509
                iter->second.connected = false;
297 andreas 510
                mMainWindow->disconnectList(iter->second.object.list);
321 andreas 511
            }
217 andreas 512
        }
296 andreas 513
    }
514
}
217 andreas 515
 
296 andreas 516
bool TObject::enableObject(ulong handle)
517
{
518
    DECL_TRACER("TObject::enableObject(ulong handle)");
519
 
349 andreas 520
    if (mObjects.empty())
521
        return false;
522
 
296 andreas 523
    map<ulong, OBJECT_t>::iterator iter = mObjects.find(handle);
524
 
525
    if (iter != mObjects.end())
526
    {
527
        if (!iter->second.object.widget)
528
        {
529
            iter->second.remove = true;
297 andreas 530
            MSG_ERROR("Object " << handleToString(iter->first) << " of type " << objectToString(iter->second.type) << " has no QObject!");
296 andreas 531
            return false;
532
        }
533
 
323 andreas 534
        TLOCKER(mutex_obj);
296 andreas 535
        iter->second.remove = false;
536
        iter->second.invalid = false;
537
 
321 andreas 538
        if (iter->second.type == OBJ_SUBVIEW && iter->second.object.area && mMainWindow && !iter->second.connected)
539
        {
297 andreas 540
            mMainWindow->reconnectArea(iter->second.object.area);
321 andreas 541
            iter->second.connected = true;
542
        }
543
        else if (iter->second.type == OBJ_LIST && iter->second.object.list && mMainWindow && !iter->second.connected)
544
        {
297 andreas 545
            mMainWindow->reconnectList(iter->second.object.list);
321 andreas 546
            iter->second.connected = true;
547
        }
297 andreas 548
 
296 andreas 549
        return true;                         // We can savely return here because a handle is unique
217 andreas 550
    }
551
 
296 andreas 552
    return false;
217 andreas 553
}
554
 
296 andreas 555
bool TObject::enableAllSubObjects(ulong handle)
556
{
557
    DECL_TRACER("::enableAllSubObjects(ulong handle)");
558
 
349 andreas 559
    if (mObjects.empty())
560
        return false;
561
 
296 andreas 562
    TLOCKER(mutex_obj);
563
    map<ulong, OBJECT_t>::iterator iter;
564
    bool ret = true;
565
 
566
    for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
567
    {
568
        if (iter->first != handle && (iter->first & 0xffff0000) == handle)
569
        {
570
            if (!iter->second.object.widget)
571
            {
572
                iter->second.remove = true;
297 andreas 573
                MSG_ERROR("Object " << handleToString(iter->first) << " of type " << objectToString(iter->second.type) << " has no QObject!");
296 andreas 574
                ret = false;
575
            }
576
            else
577
            {
578
                iter->second.remove = false;
579
                iter->second.invalid = false;
297 andreas 580
 
321 andreas 581
                if (iter->second.type == OBJ_SUBVIEW && iter->second.object.area && mMainWindow && !iter->second.connected)
582
                {
297 andreas 583
                    mMainWindow->reconnectArea(iter->second.object.area);
321 andreas 584
                    iter->second.connected = true;
585
                }
586
                else if (iter->second.type == OBJ_LIST && iter->second.object.list && mMainWindow && !iter->second.connected)
587
                {
297 andreas 588
                    mMainWindow->reconnectList(iter->second.object.list);
321 andreas 589
                    iter->second.connected = true;
590
                }
296 andreas 591
            }
592
        }
593
    }
594
 
595
    return ret;
596
}
597
 
107 andreas 598
string TObject::objectToString(TObject::OBJECT_TYPE o)
599
{
14 andreas 600
    switch(o)
601
    {
602
        case OBJ_BUTTON:  return "BUTTON"; break;
603
        case OBJ_INPUT:   return "INPUT"; break;
604
        case OBJ_NONE:    return "undefined"; break;
605
        case OBJ_PAGE:    return "PAGE"; break;
606
        case OBJ_SUBPAGE: return "SUBPAGE"; break;
607
        case OBJ_TEXT:    return "TEXT"; break;
21 andreas 608
        case OBJ_VIDEO:   return "VIDEO"; break;
200 andreas 609
        case OBJ_LIST:    return "LIST"; break;
279 andreas 610
        case OBJ_SUBVIEW: return "SUBVIEW"; break;
14 andreas 611
    }
78 andreas 612
 
107 andreas 613
    return string();   // Should not happen but is needed to satisfy the compiler.
14 andreas 614
}