File indexing completed on 2024-05-19 13:33:13

0001 /***************************************************************************
0002  *   Copyright (C) 2005 by David Saxton                                    *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #include "view.h"
0012 #include "document.h"
0013 #include "iteminterface.h"
0014 #include "ktechlab.h"
0015 #include "viewcontainer.h"
0016 #include "viewiface.h"
0017 
0018 #include <KActionCollection>
0019 #include <KLocalizedString>
0020 #include <KSqueezedTextLabel>
0021 #include <KXMLGUIFactory>
0022 
0023 #include <QApplication>
0024 #include <QPaintEvent>
0025 #include <QStyle>
0026 #include <QVBoxLayout>
0027 
0028 #include <cassert>
0029 
0030 #include <ktechlab_debug.h>
0031 
0032 // BEGIN class View
0033 View::View(Document *document, ViewContainer *viewContainer, uint viewAreaId)
0034     : QWidget(viewContainer->viewArea(viewAreaId))
0035     , KXMLGUIClient()
0036 {
0037     setObjectName("view_" + QString::number(viewAreaId));
0038     m_pFocusWidget = nullptr;
0039     m_dcopID = 0;
0040     m_viewAreaId = viewAreaId;
0041     m_pDocument = document;
0042     p_viewContainer = viewContainer;
0043     m_pViewIface = nullptr;
0044 
0045     setFocusPolicy(Qt::ClickFocus);
0046 
0047     if (ViewArea *viewArea = viewContainer->viewArea(viewAreaId))
0048         viewArea->setView(this);
0049 
0050     else
0051         qCDebug(KTL_LOG) << " viewArea = " << viewArea;
0052 
0053     m_layout = new QVBoxLayout(this);
0054     //m_layout->setMargin(0); // if we remove this some magic visibility calculation goes wrong
0055 
0056     // Don't bother creating statusbar if no ktechlab as we are not a main ktechlab tab
0057     if (KTechlab::self()) {
0058         m_statusBar = new ViewStatusBar(this);
0059 
0060         m_layout->addWidget(new KVSSBSep(this));
0061         m_layout->addWidget(m_statusBar);
0062 
0063         // connect(KTechlab::self(), SIGNAL(configurationChanged()), this, SLOT(slotUpdateConfiguration()));
0064         connect(KTechlab::self(), &KTechlab::configurationChanged, this, &View::slotUpdateConfiguration);
0065     }
0066 }
0067 
0068 View::~View()
0069 {
0070     // if ( KTechlab::self() )   // 2015.09.13 - remove the XMLGUIClient from the factory, even at program close
0071     //  KTechlab::self()->factory()->removeClient(this);
0072     // 2017.01.09: do not crash on document close. factory has its clients removed in TextDocument::~TextDocument()
0073     // if ( factory() ) {
0074     //    factory()->removeClient( this );
0075     //} else {
0076     //    qCWarning(KTL_LOG) << "Null factory";
0077     //}
0078 }
0079 
0080 QAction *View::actionByName(const QString &name) const
0081 {
0082     QAction *action = actionCollection()->action(name);
0083     if (!action)
0084         qCCritical(KTL_LOG) << "No such action: " << name;
0085     return action;
0086 }
0087 
0088 Document *View::document() const
0089 {
0090     return m_pDocument;
0091 }
0092 
0093 DCOPObject *View::dcopObject() const
0094 {
0095     return m_pViewIface;
0096 }
0097 
0098 bool View::closeView()
0099 {
0100     return p_viewContainer->closeViewArea(viewAreaId());
0101 }
0102 
0103 void View::setFocusWidget(QWidget *focusWidget)
0104 {
0105     assert(focusWidget);
0106     assert(!m_pFocusWidget);
0107 
0108     if (hasFocus())
0109         focusWidget->setFocus();
0110 
0111     m_pFocusWidget = focusWidget;
0112     setFocusProxy(m_pFocusWidget);
0113     m_pFocusWidget->installEventFilter(this);
0114     m_pFocusWidget->setFocusPolicy(Qt::ClickFocus);
0115 }
0116 
0117 bool View::eventFilter(QObject *watched, QEvent *e)
0118 {
0119     //  qCDebug(KTL_LOG) << e->type();
0120 
0121     if (watched != m_pFocusWidget)
0122         return false;
0123 
0124     switch (e->type()) {
0125     case QEvent::FocusIn: {
0126         p_viewContainer->setActiveViewArea(viewAreaId());
0127 
0128         if (KTechlab *ktl = KTechlab::self()) {
0129             ktl->actionByName("file_save")->setEnabled(true);
0130             ktl->actionByName("file_save_as")->setEnabled(true);
0131             ktl->actionByName("file_close")->setEnabled(true);
0132             ktl->actionByName("file_print")->setEnabled(true);
0133             ktl->actionByName("edit_paste")->setEnabled(true);
0134             ktl->actionByName("view_split_leftright")->setEnabled(true);
0135             ktl->actionByName("view_split_topbottom")->setEnabled(true);
0136 
0137             ItemInterface::self()->updateItemActions();
0138         }
0139 
0140         //          qCDebug(KTL_LOG) << "Focused In";
0141         emit focused(this);
0142         break;
0143     }
0144 
0145     case QEvent::FocusOut: {
0146         //          qCDebug(KTL_LOG) << "Focused Out.";
0147         QFocusEvent *fe = static_cast<QFocusEvent *>(e);
0148 
0149         if (QWidget *fw = qApp->focusWidget()) {
0150             QString fwClassName(fw->metaObject()->className());
0151             //              qCDebug(KTL_LOG) << "New focus widget is \""<<fw->name()<<"\" of type " << fwClassName;
0152 
0153             if ((fwClassName != "KateViewInternal") && (fwClassName != "QViewportWidget")) {
0154                 //                  qCDebug(KTL_LOG) << "Returning as a non-view widget has focus.";
0155                 break;
0156             }
0157         } else {
0158             //              qCDebug(KTL_LOG) << "No widget currently has focus.";
0159         }
0160 
0161         if (fe->reason() == Qt::PopupFocusReason) {
0162             //              qCDebug(KTL_LOG) << "Ignoring focus-out event as was a popup.";
0163             break;
0164         }
0165 
0166         if (fe->reason() == Qt::ActiveWindowFocusReason) {
0167             //              qCDebug(KTL_LOG) << "Ignoring focus-out event as main window lost focus.";
0168             break;
0169         }
0170 
0171         emit unfocused();
0172         break;
0173     }
0174 
0175     default:
0176         break;
0177     }
0178 
0179     return false;
0180 }
0181 
0182 void View::setDCOPID(unsigned id)
0183 {
0184     if (m_dcopID == id)
0185         return;
0186 
0187     m_dcopID = id;
0188     if (m_pViewIface) {
0189         QString docID;
0190         docID.setNum(document()->dcopID());
0191 
0192         QString viewID;
0193         viewID.setNum(dcopID());
0194 
0195         m_pViewIface->setObjId("View#" + docID + "." + viewID);
0196     }
0197 }
0198 // END class View
0199 
0200 // BEGIN class ViewStatusBar
0201 ViewStatusBar::ViewStatusBar(View *view)
0202     : QStatusBar(view)
0203 {
0204     p_view = view;
0205 
0206     m_modifiedLabel = new QLabel(this);
0207     addWidget(m_modifiedLabel, 0 /*, false */);
0208     m_fileNameLabel = new KSqueezedTextLabel(this);
0209     addWidget(m_fileNameLabel, 1 /*, false */);
0210     m_statusLabel = new QLabel(this);
0211     m_statusLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
0212     addPermanentWidget(m_statusLabel, 0);
0213 
0214     const int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize);
0215     m_modifiedPixmap = QIcon::fromTheme("document-save").pixmap(iconSize);
0216     m_unmodifiedPixmap = QIcon::fromTheme("null").pixmap(iconSize);
0217 
0218     connect(view->document(), &Document::modifiedStateChanged, this, &ViewStatusBar::slotModifiedStateChanged);
0219     connect(view->document(), &Document::fileNameChanged, this, &ViewStatusBar::slotFileNameChanged);
0220 
0221     connect(view, &View::focused, this, &ViewStatusBar::slotViewFocused);
0222     connect(view, &View::unfocused, this, &ViewStatusBar::slotViewUnfocused);
0223 
0224     slotModifiedStateChanged();
0225     slotFileNameChanged(view->document()->url());
0226 
0227     slotViewUnfocused();
0228 }
0229 
0230 void ViewStatusBar::setStatusText(const QString &statusText)
0231 {
0232     m_statusLabel->setText(statusText);
0233 }
0234 
0235 void ViewStatusBar::slotModifiedStateChanged()
0236 {
0237     m_modifiedLabel->setPixmap(p_view->document()->isModified() ? m_modifiedPixmap : m_unmodifiedPixmap);
0238 }
0239 
0240 void ViewStatusBar::slotFileNameChanged(const QUrl &url)
0241 {
0242     m_fileNameLabel->setText(url.isEmpty() ? i18n("Untitled") : url.adjusted(QUrl::StripTrailingSlash).fileName());
0243 }
0244 
0245 void ViewStatusBar::slotViewFocused(View *)
0246 {
0247     setPalette(p_view->palette());
0248 }
0249 
0250 void ViewStatusBar::slotViewUnfocused()
0251 {
0252     QPalette pal(p_view->palette());
0253     pal.setColor(QPalette::Window /*QColorGroup::Background */, pal.mid().color());
0254     pal.setColor(QPalette::Light, pal.midlight().color());
0255     setPalette(pal);
0256 }
0257 // END class ViewStatusBar
0258 
0259 // BEGIN class KVSSBSep
0260 void KVSSBSep::paintEvent(QPaintEvent *e)
0261 {
0262     // QPainter p( this );
0263     QPainter p;
0264     const bool beginSuccess = p.begin(this);
0265     if (!beginSuccess) {
0266         qCWarning(KTL_LOG) << " painter is not active";
0267     }
0268     // p.setPen( colorGroup().shadow() );
0269     // QColorGroup colorGroup(palette()); // 2018.12.02
0270     p.setPen(palette().shadow().color() /* colorGroup.shadow() */);
0271     p.drawLine(e->rect().left(), 0, e->rect().right(), 0);
0272     // p.setPen( ((View*)parentWidget())->hasFocus() ? colorGroup.light() : colorGroup.midlight() );
0273     View *parentView = dynamic_cast<View *>(parentWidget());
0274     if (!parentView) {
0275         qCWarning(KTL_LOG) << "parent not View for this=" << this << ", parent=" << parentWidget();
0276         return;
0277     }
0278     p.setPen(parentView->hasFocus() ? palette().light().color() : palette().midlight().color());
0279     p.drawLine(e->rect().left(), 1, e->rect().right(), 1);
0280 }
0281 // END  class KVSSBSep
0282 
0283 #include "moc_view.cpp"