226 lines
4.8 KiB
C++
Executable File
226 lines
4.8 KiB
C++
Executable File
// TODO: hdr
|
|
|
|
#include "lts_global_wait_dialog.h"
|
|
#include "lts_progress_dialog_helper.h"
|
|
#include "lts_overlay_loading.h"
|
|
#include "lts_dialog.h"
|
|
#include "lts_frameless_dialog.h"
|
|
|
|
#include <QCoreApplication>
|
|
#include <QTimer>
|
|
//#include <QDebug>
|
|
|
|
#ifdef Q_OS_UNIX
|
|
#include <execinfo.h> // backtrace(..)
|
|
#include <dlfcn.h> // dladdr(..)
|
|
#include <cxxabi.h> // demangle
|
|
#endif
|
|
|
|
|
|
namespace LtsWidgets
|
|
{
|
|
|
|
LtsGlobalWaitDialog::~LtsGlobalWaitDialog()
|
|
{
|
|
delete m_progressDialog;
|
|
}
|
|
|
|
|
|
LtsGlobalWaitDialog::LtsGlobalWaitDialog()
|
|
: m_waitingCount(0)
|
|
, m_visible(true)
|
|
, m_progressDialog(new LtsProgressDialogHelper(nullptr))
|
|
, m_hideTimer(new QTimer(this)) // avoids blinking windows by waiting a little until the wait window will be hidden
|
|
{
|
|
m_hideTimer->setSingleShot(true);
|
|
m_hideTimer->setInterval(500);
|
|
connect(m_hideTimer, &QTimer::timeout,
|
|
this, &LtsGlobalWaitDialog::hideIt);
|
|
}
|
|
|
|
|
|
void LtsGlobalWaitDialog::unarm()
|
|
{
|
|
m_armed = false;
|
|
hideIt(); // force hide it (don't worry, does nothing if now shown)
|
|
}
|
|
|
|
|
|
void LtsGlobalWaitDialog::rearm()
|
|
{
|
|
m_armed = true;
|
|
setVisible(true); // show again (if some component is still waiting)
|
|
}
|
|
|
|
|
|
void LtsGlobalWaitDialog::setVisible(bool visible)
|
|
{
|
|
if (m_waitingCount > 0 && visible)
|
|
showIt();
|
|
|
|
if (m_waitingCount < 1 && !visible)
|
|
hideIt();
|
|
}
|
|
|
|
|
|
void LtsGlobalWaitDialog::showIt()
|
|
{
|
|
if (m_progressDialog->isShown())
|
|
return;
|
|
|
|
m_hideTimer->stop();
|
|
if (m_armed)
|
|
{
|
|
m_progressDialog->slotShowWaitForReplyWindow();
|
|
}
|
|
}
|
|
|
|
|
|
void LtsGlobalWaitDialog::hideIt()
|
|
{
|
|
if (!m_progressDialog->isShown())
|
|
return;
|
|
|
|
m_hideTimer->stop();
|
|
m_progressDialog->slotStopWaitForReplyWindow();
|
|
}
|
|
|
|
|
|
void bt()
|
|
{
|
|
#ifdef Q_OS_UNIX
|
|
void *callstack[128];
|
|
const int nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
|
|
int nFrames = backtrace(callstack, nMaxFrames);
|
|
char **symbols = backtrace_symbols(callstack, nFrames);
|
|
|
|
for (int i = 1; i < nFrames; i++)
|
|
{
|
|
QString address(QStringLiteral("0x%1").arg(QString::number(*(quintptr *)callstack[i], 16)));
|
|
QString function;
|
|
int offset = -1; // aka. invalid
|
|
|
|
Dl_info info;
|
|
if (dladdr(callstack[i], &info) && info.dli_sname)
|
|
{
|
|
char *demangled = nullptr;
|
|
int status = -1;
|
|
if (info.dli_sname[0] == '_')
|
|
demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status);
|
|
|
|
function = QString::fromUtf8(status == 0 ? demangled : info.dli_sname == 0 ? symbols[i] : info.dli_sname);
|
|
offset = (char *)callstack[i] - (char *)info.dli_saddr;
|
|
|
|
free(demangled);
|
|
}
|
|
else
|
|
{
|
|
function = QString::fromUtf8(symbols[i]);
|
|
}
|
|
|
|
//qWarning() << "frame" << i << address << function << offset;
|
|
}
|
|
|
|
free(symbols);
|
|
|
|
// if (nFrames == nMaxFrames)
|
|
// qWarning() << "[BACKTRACE TRUNCATED]";
|
|
#endif
|
|
}
|
|
|
|
|
|
void LtsGlobalWaitDialog::wait(QWidget *parent, const QString &customText)
|
|
{
|
|
m_progressDialog->setParentWidget(parent);
|
|
if (m_waitingCount < 1 && m_visible) // nothing is waiting
|
|
showIt();
|
|
|
|
setCustomText(customText);
|
|
|
|
m_waitingCount++; // count even if not visible !
|
|
|
|
//qWarning() << "LtsGlobalWaitDialog ++" << m_waitingCount;
|
|
|
|
//bt();
|
|
}
|
|
|
|
|
|
void LtsGlobalWaitDialog::setCustomText(const QString &customText)
|
|
{
|
|
m_progressDialog->setCustomText(customText);
|
|
}
|
|
|
|
|
|
void LtsGlobalWaitDialog::done()
|
|
{
|
|
if (m_waitingCount == 0)
|
|
{
|
|
//qWarning() << "LtsGlobalWaitDialog: called done() while there is nothing waiting!";
|
|
m_hideTimer->start();
|
|
return;
|
|
}
|
|
|
|
Q_ASSERT(m_waitingCount > 0);
|
|
|
|
m_waitingCount--;
|
|
//qWarning() << "LtsGlobalWaitDialog --" << m_waitingCount;
|
|
|
|
if (m_waitingCount == 0) // no more waiting classes
|
|
m_hideTimer->start();
|
|
}
|
|
|
|
static LtsGlobalWaitDialog *s_gwdInstance = nullptr;
|
|
void LtsGlobalWaitDialog::cleanupGwdInstance()
|
|
{
|
|
delete s_gwdInstance;
|
|
s_gwdInstance = nullptr;
|
|
}
|
|
|
|
LtsGlobalWaitDialog *LtsGlobalWaitDialog::getInstance()
|
|
{
|
|
if (!s_gwdInstance)
|
|
{
|
|
s_gwdInstance = new LtsGlobalWaitDialog;
|
|
qAddPostRoutine(&LtsGlobalWaitDialog::cleanupGwdInstance);
|
|
}
|
|
return s_gwdInstance;
|
|
}
|
|
} // namespace LtsWidgets
|
|
|
|
|
|
/// Waiter
|
|
Waiter::Waiter(const QString &customText)
|
|
{
|
|
LtsWidgets::LtsGlobalWaitDialog::getInstance()->wait(nullptr, customText);
|
|
}
|
|
|
|
|
|
Waiter::Waiter(LtsWidgets::LtsDialog *parent, const QString &customText)
|
|
: m_parent(parent)
|
|
{
|
|
m_oldClosableState = m_parent->isClosable();
|
|
m_parent->setClosable(false);
|
|
m_parent->setCurrentlyBlocking(true);
|
|
auto *wait = new LtsWidgets::LtsOverlayLoading;
|
|
wait->setText(customText.isEmpty() ? QObject::tr("Waiting for server reply...") : customText);
|
|
m_parent->setOverlay(wait);
|
|
m_loadingOverlay = wait;
|
|
}
|
|
|
|
|
|
Waiter::~Waiter()
|
|
{
|
|
if (m_loadingOverlay == nullptr)
|
|
{
|
|
LtsWidgets::LtsGlobalWaitDialog::getInstance()->done();
|
|
return;
|
|
}
|
|
|
|
m_parent->setClosable(m_oldClosableState);
|
|
m_parent->setCurrentlyBlocking(false);
|
|
m_loadingOverlay->deleteLater();
|
|
}
|
|
|
|
|
|
|