File indexing completed on 2024-05-05 04:19:19
0001 // vim: set tabstop=4 shiftwidth=4 expandtab: 0002 /* 0003 Gwenview: an image viewer 0004 Copyright 2007 Aurélien Gâteau <agateau@kde.org> 0005 0006 This program is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU General Public License 0008 as published by the Free Software Foundation; either version 2 0009 of the License, or (at your option) any later version. 0010 0011 This program is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 GNU General Public License for more details. 0015 0016 You should have received a copy of the GNU General Public License 0017 along with this program; if not, write to the Free Software 0018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 0019 0020 */ 0021 // Self 0022 #include "savebar.h" 0023 0024 // Qt 0025 #include <QHBoxLayout> 0026 #include <QIcon> 0027 #include <QLabel> 0028 #include <QToolButton> 0029 #include <QToolTip> 0030 #include <QUrl> 0031 0032 // KF 0033 #include <KActionCollection> 0034 #include <KColorScheme> 0035 #include <KIconLoader> 0036 #include <KLocalizedString> 0037 0038 // Local 0039 #include "gwenview_app_debug.h" 0040 #include "lib/document/documentfactory.h" 0041 #include "lib/gwenviewconfig.h" 0042 #include "lib/memoryutils.h" 0043 #include "lib/paintutils.h" 0044 0045 namespace Gwenview 0046 { 0047 QToolButton *createToolButton() 0048 { 0049 auto button = new QToolButton; 0050 button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); 0051 button->hide(); 0052 return button; 0053 } 0054 0055 struct SaveBarPrivate { 0056 SaveBar *q = nullptr; 0057 KActionCollection *mActionCollection = nullptr; 0058 QWidget *mSaveBarWidget = nullptr; 0059 QWidget *mTopRowWidget = nullptr; 0060 QToolButton *mUndoButton = nullptr; 0061 QToolButton *mRedoButton = nullptr; 0062 QToolButton *mSaveCurrentUrlButton = nullptr; 0063 QToolButton *mSaveAsButton = nullptr; 0064 QToolButton *mSaveAllButton = nullptr; 0065 QToolButton *mSaveAllFullScreenButton = nullptr; 0066 QLabel *mMessageLabel = nullptr; 0067 QLabel *mActionsLabel = nullptr; 0068 QFrame *mTooManyChangesFrame = nullptr; 0069 QUrl mCurrentUrl; 0070 0071 void createTooManyChangesFrame() 0072 { 0073 mTooManyChangesFrame = new QFrame; 0074 0075 // Icon 0076 auto iconLabel = new QLabel; 0077 QPixmap pix = QIcon::fromTheme(QStringLiteral("dialog-warning")).pixmap(KIconLoader::SizeSmall); 0078 iconLabel->setPixmap(pix); 0079 0080 // Text label 0081 auto textLabel = new QLabel; 0082 textLabel->setText(i18n("You have modified many images. To avoid memory problems, you should save your changes.")); 0083 0084 mSaveAllFullScreenButton = createToolButton(); 0085 0086 // Layout 0087 auto layout = new QHBoxLayout(mTooManyChangesFrame); 0088 layout->setContentsMargins(0, 0, 0, 0); 0089 layout->addWidget(iconLabel); 0090 layout->addWidget(textLabel); 0091 layout->addWidget(mSaveAllFullScreenButton); 0092 mTooManyChangesFrame->hide(); 0093 0094 // CSS 0095 KColorScheme scheme(mSaveBarWidget->palette().currentColorGroup(), KColorScheme::Window); 0096 QColor warningBackgroundColor = scheme.background(KColorScheme::NegativeBackground).color(); 0097 QColor warningBorderColor = PaintUtils::adjustedHsv(warningBackgroundColor, 0, 150, 0); 0098 QColor warningColor = scheme.foreground(KColorScheme::NegativeText).color(); 0099 0100 QString css = 0101 ".QFrame {" 0102 " background-color: %1;" 0103 " border: 1px solid %2;" 0104 " border-radius: 4px;" 0105 " padding: 3px;" 0106 "}" 0107 ".QFrame QLabel {" 0108 " color: %3;" 0109 "}"; 0110 css = css.arg(warningBackgroundColor.name(), warningBorderColor.name(), warningColor.name()); 0111 mTooManyChangesFrame->setStyleSheet(css); 0112 } 0113 0114 void applyNormalStyleSheet() 0115 { 0116 const QColor bgColor = QToolTip::palette().base().color(); 0117 const QColor borderColor = PaintUtils::adjustedHsv(bgColor, 0, 150, 0); 0118 const QColor fgColor = QToolTip::palette().text().color(); 0119 0120 QString css = 0121 "#saveBarWidget {" 0122 " background-color: %1;" 0123 " border-top: 1px solid %2;" 0124 " border-bottom: 1px solid %2;" 0125 " color: %3;" 0126 "}"; 0127 0128 css = css.arg(bgColor.name(), borderColor.name(), fgColor.name()); 0129 mSaveBarWidget->setStyleSheet(css); 0130 } 0131 0132 void applyFullScreenStyleSheet() 0133 { 0134 const QString css = 0135 "#saveBarWidget {" 0136 " background-color: #333;" 0137 "}"; 0138 mSaveBarWidget->setStyleSheet(css); 0139 } 0140 0141 void updateTooManyChangesFrame(const QList<QUrl> &list) 0142 { 0143 qreal maxPercentageOfMemoryUsage = GwenviewConfig::percentageOfMemoryUsageWarning(); 0144 qulonglong maxMemoryUsage = MemoryUtils::getTotalMemory() * maxPercentageOfMemoryUsage; 0145 qulonglong memoryUsage = 0; 0146 for (const QUrl &url : list) { 0147 Document::Ptr doc = DocumentFactory::instance()->load(url); 0148 memoryUsage += doc->memoryUsage(); 0149 } 0150 0151 mTooManyChangesFrame->setVisible(memoryUsage > maxMemoryUsage); 0152 } 0153 0154 void updateTopRowWidget(const QList<QUrl> &lst) 0155 { 0156 QStringList links; 0157 QString message; 0158 0159 if (lst.contains(mCurrentUrl)) { 0160 message = i18n("Current image modified"); 0161 0162 mUndoButton->show(); 0163 mRedoButton->show(); 0164 0165 if (lst.size() > 1) { 0166 QString previous = i18n("Previous modified image"); 0167 QString next = i18n("Next modified image"); 0168 if (mCurrentUrl == lst[0]) { 0169 links << previous; 0170 } else { 0171 links << QStringLiteral("<a href='previous'>%1</a>").arg(previous); 0172 } 0173 if (mCurrentUrl == lst[lst.size() - 1]) { 0174 links << next; 0175 } else { 0176 links << QStringLiteral("<a href='next'>%1</a>").arg(next); 0177 } 0178 } 0179 } else { 0180 mUndoButton->hide(); 0181 mRedoButton->hide(); 0182 0183 message = i18np("One image modified", "%1 images modified", lst.size()); 0184 if (lst.size() > 1) { 0185 links << QStringLiteral("<a href='first'>%1</a>").arg(i18n("Go to first modified image")); 0186 } else { 0187 links << QStringLiteral("<a href='first'>%1</a>").arg(i18n("Go to it")); 0188 } 0189 } 0190 0191 mSaveCurrentUrlButton->setVisible(lst.contains(mCurrentUrl)); 0192 mSaveAsButton->setVisible(lst.contains(mCurrentUrl)); 0193 mSaveAllButton->setVisible(lst.size() >= 1); 0194 0195 mMessageLabel->setText(message); 0196 mMessageLabel->setMaximumWidth(mMessageLabel->minimumSizeHint().width()); 0197 mActionsLabel->setText(links.join(QStringLiteral(" | "))); 0198 } 0199 0200 void updateWidgetSizes() 0201 { 0202 auto layout = static_cast<QVBoxLayout *>(mSaveBarWidget->layout()); 0203 int topRowHeight = q->window()->isFullScreen() ? 0 : mTopRowWidget->height(); 0204 int bottomRowHeight = mTooManyChangesFrame->isVisibleTo(mSaveBarWidget) ? mTooManyChangesFrame->sizeHint().height() : 0; 0205 0206 int height = 2 * layout->contentsMargins().top() + layout->contentsMargins().bottom() + topRowHeight + bottomRowHeight; 0207 if (topRowHeight > 0 && bottomRowHeight > 0) { 0208 height += layout->spacing(); 0209 } 0210 mSaveBarWidget->setFixedHeight(height); 0211 } 0212 }; 0213 0214 SaveBar::SaveBar(QWidget *parent, KActionCollection *actionCollection) 0215 : SlideContainer(parent) 0216 , d(new SaveBarPrivate) 0217 { 0218 d->q = this; 0219 d->mActionCollection = actionCollection; 0220 d->mSaveBarWidget = new QWidget(); 0221 d->mSaveBarWidget->setObjectName(QStringLiteral("saveBarWidget")); 0222 d->applyNormalStyleSheet(); 0223 0224 d->mMessageLabel = new QLabel; 0225 d->mMessageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); 0226 0227 d->mUndoButton = createToolButton(); 0228 d->mRedoButton = createToolButton(); 0229 d->mSaveCurrentUrlButton = createToolButton(); 0230 d->mSaveAsButton = createToolButton(); 0231 d->mSaveAllButton = createToolButton(); 0232 0233 d->mActionsLabel = new QLabel; 0234 d->mActionsLabel->setAlignment(Qt::AlignCenter); 0235 d->mActionsLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); 0236 0237 d->createTooManyChangesFrame(); 0238 0239 // Setup top row 0240 d->mTopRowWidget = new QWidget; 0241 auto rowLayout = new QHBoxLayout(d->mTopRowWidget); 0242 rowLayout->addWidget(d->mMessageLabel); 0243 rowLayout->setStretchFactor(d->mMessageLabel, 1); 0244 rowLayout->addWidget(d->mUndoButton); 0245 rowLayout->addWidget(d->mRedoButton); 0246 rowLayout->addWidget(d->mActionsLabel); 0247 rowLayout->addWidget(d->mSaveCurrentUrlButton); 0248 rowLayout->addWidget(d->mSaveAsButton); 0249 rowLayout->addWidget(d->mSaveAllButton); 0250 rowLayout->setContentsMargins(0, 0, 0, 0); 0251 0252 // Setup bottom row 0253 auto bottomRowLayout = new QHBoxLayout; 0254 bottomRowLayout->addStretch(); 0255 bottomRowLayout->addWidget(d->mTooManyChangesFrame); 0256 bottomRowLayout->addStretch(); 0257 0258 // Gather everything together 0259 auto layout = new QVBoxLayout(d->mSaveBarWidget); 0260 layout->addWidget(d->mTopRowWidget); 0261 layout->addLayout(bottomRowLayout); 0262 layout->setContentsMargins(3, 3, 3, 3); 0263 layout->setSpacing(3); 0264 0265 setContent(d->mSaveBarWidget); 0266 0267 connect(DocumentFactory::instance(), &DocumentFactory::modifiedDocumentListChanged, this, &SaveBar::updateContent); 0268 0269 connect(d->mActionsLabel, &QLabel::linkActivated, this, &SaveBar::triggerAction); 0270 } 0271 0272 SaveBar::~SaveBar() 0273 { 0274 delete d; 0275 } 0276 0277 void SaveBar::initActionDependentWidgets() 0278 { 0279 d->mUndoButton->setDefaultAction(d->mActionCollection->action(QStringLiteral("edit_undo"))); 0280 d->mRedoButton->setDefaultAction(d->mActionCollection->action(QStringLiteral("edit_redo"))); 0281 d->mSaveCurrentUrlButton->setDefaultAction(d->mActionCollection->action(QStringLiteral("file_save"))); 0282 d->mSaveAsButton->setDefaultAction(d->mActionCollection->action(QStringLiteral("file_save_as"))); 0283 0284 // FIXME: Not using an action for now 0285 d->mSaveAllButton->setText(i18n("Save All")); 0286 d->mSaveAllButton->setToolTip(i18nc("@info:tooltip", "Save all modified images")); 0287 d->mSaveAllButton->setIcon(QIcon::fromTheme(QStringLiteral("document-save-all"))); 0288 connect(d->mSaveAllButton, &QToolButton::clicked, this, &SaveBar::requestSaveAll); 0289 0290 d->mSaveAllFullScreenButton->setText(i18n("Save All")); 0291 connect(d->mSaveAllFullScreenButton, &QToolButton::clicked, this, &SaveBar::requestSaveAll); 0292 0293 int height = d->mUndoButton->sizeHint().height(); 0294 d->mTopRowWidget->setFixedHeight(height); 0295 d->updateWidgetSizes(); 0296 } 0297 0298 void SaveBar::setFullScreenMode(bool isFullScreen) 0299 { 0300 d->mSaveAllFullScreenButton->setVisible(isFullScreen); 0301 if (isFullScreen) { 0302 d->applyFullScreenStyleSheet(); 0303 } else { 0304 d->applyNormalStyleSheet(); 0305 } 0306 updateContent(); 0307 } 0308 0309 void SaveBar::updateContent() 0310 { 0311 QList<QUrl> lst = DocumentFactory::instance()->modifiedDocumentList(); 0312 0313 if (window()->isFullScreen()) { 0314 d->mTopRowWidget->hide(); 0315 } else { 0316 d->mTopRowWidget->show(); 0317 d->updateTopRowWidget(lst); 0318 } 0319 0320 d->updateTooManyChangesFrame(lst); 0321 0322 d->updateWidgetSizes(); 0323 if (lst.isEmpty() || (window()->isFullScreen() && !d->mTooManyChangesFrame->isVisibleTo(d->mSaveBarWidget))) { 0324 slideOut(); 0325 } else { 0326 slideIn(); 0327 } 0328 } 0329 0330 void SaveBar::triggerAction(const QString &action) 0331 { 0332 QList<QUrl> lst = DocumentFactory::instance()->modifiedDocumentList(); 0333 if (action == QLatin1String("first")) { 0334 Q_EMIT goToUrl(lst[0]); 0335 } else if (action == QLatin1String("previous")) { 0336 int pos = lst.indexOf(d->mCurrentUrl); 0337 --pos; 0338 Q_ASSERT(pos >= 0); 0339 Q_EMIT goToUrl(lst[pos]); 0340 } else if (action == QLatin1String("next")) { 0341 int pos = lst.indexOf(d->mCurrentUrl); 0342 ++pos; 0343 Q_ASSERT(pos < lst.size()); 0344 Q_EMIT goToUrl(lst[pos]); 0345 } else { 0346 qCWarning(GWENVIEW_APP_LOG) << "Unknown action: " << action; 0347 } 0348 } 0349 0350 void SaveBar::setCurrentUrl(const QUrl &url) 0351 { 0352 d->mCurrentUrl = url; 0353 updateContent(); 0354 } 0355 0356 } // namespace 0357 0358 #include "moc_savebar.cpp"