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