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