/* * IdealIRC - Internet Relay Chat client * Copyright (C) 2019 Tom-Andre Barstad * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "IWin/IWinStatus.h" #include "IWin/IWinChannel.h" #include "IWin/IWinPrivate.h" #include "MdiManager.h" #include "ConfigMgr.h" #include <QApplication> #include <QDebug> namespace { constexpr int WINDOW_DEFAULT_WIDTH = 800; constexpr int WINDOW_DEFAULT_HEIGHT = 600; constexpr int WINDOW_STEP = 30; constexpr int WINDOW_STEP_RESET_POSITION = 400; constexpr int WINDOW_STEP_RESET_ADJUST = 60; } MdiManager* MdiManager::m_instance{ nullptr }; MdiManager::MdiManager(QMdiArea& mdiArea, QToolBar& buttonBar, QSystemTrayIcon& trayIcon) : m_mdiArea(mdiArea) , trayIcon(trayIcon) , m_bbMgr(&buttonBar) { m_instance = this; connect(&m_mdiArea, &QMdiArea::subWindowActivated, this, &MdiManager::subwinActivated); connect(&m_bbMgr, &ButtonbarMgr::changeWindow, &m_mdiArea, &QMdiArea::setActiveSubWindow); } MdiManager& MdiManager::instance() { return *m_instance; } MdiManager::ButtonBarEntry::ButtonBarEntry(QAction* button_, const QString& buttonText, QMdiSubWindow* parent) : subwin(parent) , button(button_) { menu = new QMenu(parent); menuHead = menu->addAction(buttonText); QFont f = menuHead->font(); f.setBold(true); menuHead->setFont(f); menuHead->setDisabled(true); menuSep = menu->addSeparator(); menuClose = menu->addAction(tr("Close")); connect(menuClose, &QAction::triggered, [&](bool){ subwin->close(); }); } IWin* MdiManager::createSubwindow(IWin* parent, const QString& buttonText, IWin::Type windowType, bool activate) { IWin* basePtr{ nullptr }; IWinStatus* statusParent{ nullptr }; QMdiSubWindow* mdiwin{ nullptr }; if (parent && parent->getType() == IWin::Type::Status) statusParent = dynamic_cast<IWinStatus*>(parent); switch (windowType) { case IWin::Type::Status: basePtr = new IWinStatus(buttonText); m_activeStatus = dynamic_cast<IWinStatus*>(basePtr); break; case IWin::Type::Channel: basePtr = new IWinChannel(statusParent, buttonText); break; case IWin::Type::Private: basePtr = new IWinPrivate(statusParent, buttonText); break; case IWin::Type::Custom: [[fallthrough]]; // Use createCustomSubwindow; treat this as an error. case IWin::Type::Undefined: break; } if (!basePtr) { qWarning() << "Failed to create subwindow of type" << IWin::TypeString[windowType] << "with button text" << buttonText; return nullptr; } connect(basePtr, &IWin::aboutToClose, this, &MdiManager::subwinAboutToClose); mdiwin = m_mdiArea.addSubWindow(basePtr, Qt::SubWindow); mdiwin->setAttribute(Qt::WA_DeleteOnClose); m_bbMgr.addButton(basePtr, mdiwin); QRect spawnCoord = generateSpawnCoordinates(); mdiwin->setGeometry(spawnCoord); qInfo() << "Created a subwindow of type" << IWin::TypeString[windowType] << "with button text" << buttonText; if (!m_active || m_active->isMaximized()) mdiwin->showMaximized(); else mdiwin->show(); if (!activate) { m_mdiArea.activatePreviousSubWindow(); mdiwin->lower(); } return basePtr; } IWin* MdiManager::currentWindow() const { return m_active; } IWinStatus* MdiManager::currentStatus() const { return m_activeStatus; } IWin* MdiManager::findWindow(IWin* statusParent, const QString& buttonText) { for (QMdiSubWindow* mdiwin : m_mdiArea.subWindowList()) { IWin* subwin = dynamic_cast<IWin*>(mdiwin->widget()); if (subwin->getParent() == statusParent && buttonText.compare(subwin->getButtonText(), Qt::CaseInsensitive) == 0) { subwin->setButtonText(buttonText); renameWindowButton(subwin, buttonText); return subwin; } } return nullptr; } QMdiSubWindow* MdiManager::toMdiwin(IWin* win) { for (QMdiSubWindow* mdiwin : m_mdiArea.subWindowList()) { if (mdiwin->widget() == win) return mdiwin; } return nullptr; } QList<QMdiSubWindow*> MdiManager::mdiChildrenOf(const IWin* statusParent, IWin::Type type) const { QList<QMdiSubWindow*> retlist; for (QMdiSubWindow* mdiwin : m_mdiArea.subWindowList()) { IWin* subwin = dynamic_cast<IWin*>(mdiwin->widget()); if (type != IWin::Type::Undefined && subwin->getType() != type) continue; if (subwin->getParent() == statusParent) retlist.push_back(mdiwin); } return retlist; } QList<IWin*> MdiManager::childrenOf(const IWin* statusParent, IWin::Type type) const { QList<IWin*> retlist; QList<QMdiSubWindow*> subwinList = mdiChildrenOf(statusParent, type); for (QMdiSubWindow* subwin : subwinList) retlist.push_back(qobject_cast<IWin*>(subwin->widget())); return retlist; } void MdiManager::showTrayInfo(const QString& title, const QString& message) { showTray(title, message, QSystemTrayIcon::MessageIcon::Information); } void MdiManager::showTrayWarn(const QString& title, const QString& message) { showTray(title, message, QSystemTrayIcon::MessageIcon::Warning); } int MdiManager::connectionsOnlineCount() const { int c = 0; for (QMdiSubWindow* mdiwin : m_mdiArea.subWindowList()) { IWin* subwin = dynamic_cast<IWin*>(mdiwin->widget()); if (subwin->getType() != IWin::Type::Status) continue; IWinStatus* status = dynamic_cast<IWinStatus*>(subwin); if (status->getConnection().isOnline()) ++c; } return c; } void MdiManager::broadcastProgramExit() { for (QMdiSubWindow* mdiwin : m_mdiArea.subWindowList()) { IWin* subwin = dynamic_cast<IWin*>(mdiwin->widget()); if (subwin->getType() != IWin::Type::Status) continue; IWinStatus* status = dynamic_cast<IWinStatus*>(subwin); if (status->getConnection().isOnline()) { connect(&status->getConnection(), &IRC::readyForExit, [this](){ if (connectionsOnlineCount() == 0) emit readyForExit(); }); ConfigMgr& conf = ConfigMgr::instance(); status->getConnection().disconnectForExit(conf.common("QuitMessage")); } } } void MdiManager::renameWindowButton(IWin* window, const QString& text) { m_bbMgr.reloadButtonName(window, text); } void MdiManager::print(IWinStatus* parent, const QString& target, const PrintType ptype, const QString& text) { IWin* subwin = findWindow(parent, target); if (!subwin || !subwin->print(ptype, text)) { if (ptype != PrintType::CTCP) parent->print(ptype, QStringLiteral("[%1] %2").arg(target).arg(text)); else parent->print(ptype, text); } } void MdiManager::print(const QString& target, const PrintType ptype, const QString& text) { print(m_activeStatus, target, ptype, text); } void MdiManager::printToActive(IWinStatus* parent, const PrintType ptype, const QString& text) { if (!m_active) parent->print(ptype, text); else if (m_active->getParent() != parent) parent->print(ptype, text); else m_active->print(ptype, text); } void MdiManager::printToTypes(IWinStatus* parent, const IWin::Type toType, const PrintType ptype, const QString& text) { for (QMdiSubWindow* mdiwin : m_mdiArea.subWindowList()) { IWin* subwin = qobject_cast<IWin*>(mdiwin->widget()); if (subwin->getParent() == parent && subwin->getType() == toType) subwin->print(ptype, text); } } void MdiManager::printToAll(IWinStatus* parent, const PrintType ptype, const QString& text) { for (QMdiSubWindow* mdiwin : m_mdiArea.subWindowList()) { IWin* subwin = qobject_cast<IWin*>(mdiwin->widget()); if (subwin->getParent() == parent || subwin == parent) subwin->print(ptype, text); } } void MdiManager::showTray(const QString& title, const QString& message, QSystemTrayIcon::MessageIcon icon) { if (QApplication::activeWindow() || QApplication::focusWidget()) return; ConfigMgr& conf = ConfigMgr::instance(); if (conf.common("TrayNotify") != "1") return; int delay = conf.common("TrayNotifyDelay").toInt(); trayIcon.showMessage(title, message, icon, delay*1000); } void MdiManager::subwinAboutToClose(IWin* who) { qInfo() << "Closing" << who; m_bbMgr.delButton(who); } void MdiManager::subwinActivated(QMdiSubWindow* window) { if (!window) return; IWin* cw = dynamic_cast<IWin*>(window->widget()); qInfo() << "Activated:" << cw; if (!cw) { qWarning() << "NULL window!"; return; } m_bbMgr.subwinActivated(m_active, cw); m_active = cw; if (cw->getParent() && cw->getParent()->getType() == IWin::Type::Status) m_activeStatus = dynamic_cast<IWinStatus*>(cw->getParent()); else if (cw->getType() == IWin::Type::Status) m_activeStatus = qobject_cast<IWinStatus*>(cw); emit subwindowSwitched(); } QRect MdiManager::generateSpawnCoordinates() { QRect rectangle(nextXY, nextXY, WINDOW_DEFAULT_WIDTH, WINDOW_DEFAULT_HEIGHT); nextXY += WINDOW_STEP; if (nextXY > WINDOW_STEP_RESET_POSITION) { nextXYadjust += WINDOW_STEP_RESET_ADJUST; if (nextXYadjust > WINDOW_STEP_RESET_POSITION) nextXYadjust = 0; nextXY = nextXYadjust; } return rectangle; }