File indexing completed on 2025-01-05 03:51:59
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2003-11-03 0007 * Description : painter class to draw calendar. 0008 * 0009 * SPDX-FileCopyrightText: 2003-2005 by Renchi Raju <renchi dot raju at gmail dot com> 0010 * SPDX-FileCopyrightText: 2007-2008 by Orgad Shaneh <orgads at gmail dot com> 0011 * SPDX-FileCopyrightText: 2012 by Angelo Naselli <anaselli at linux dot it> 0012 * SPDX-FileCopyrightText: 2012-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0013 * 0014 * SPDX-License-Identifier: GPL-2.0-or-later 0015 * 0016 * ============================================================ */ 0017 0018 #include "calpainter.h" 0019 0020 // Qt includes 0021 0022 #include <QDate> 0023 #include <QFileInfo> 0024 #include <QPointer> 0025 #include <QPaintDevice> 0026 #include <QRect> 0027 #include <QString> 0028 #include <QUrl> 0029 #include <QImage> 0030 #include <QLocale> 0031 #include <QScopedPointer> 0032 0033 // Local includes 0034 0035 #include "calsettings.h" 0036 #include "calsystem.h" 0037 #include "digikam_debug.h" 0038 #include "metaengine.h" 0039 #include "dimg.h" 0040 #include "previewloadthread.h" 0041 0042 using namespace Digikam; 0043 0044 namespace DigikamGenericCalendarPlugin 0045 { 0046 0047 class Q_DECL_HIDDEN CalPainter::Private 0048 { 0049 public: 0050 0051 explicit Private() 0052 : cancelled (false), 0053 orientation(MetaEngine::ORIENTATION_UNSPECIFIED) 0054 { 0055 } 0056 0057 bool cancelled; 0058 0059 int orientation; 0060 0061 QImage image; 0062 QUrl imagePath; 0063 }; 0064 0065 CalPainter::CalPainter(QPaintDevice* const pDevice) 0066 : QPainter(pDevice), 0067 d (new Private) 0068 { 0069 } 0070 0071 CalPainter::~CalPainter() 0072 { 0073 delete d; 0074 } 0075 0076 void CalPainter::cancel() 0077 { 0078 d->cancelled = true; 0079 } 0080 0081 void CalPainter::setImage(const QUrl& imagePath) 0082 { 0083 d->imagePath = imagePath; 0084 QScopedPointer<MetaEngine> meta(new MetaEngine(d->imagePath.toLocalFile())); 0085 d->orientation = (int)meta->getItemOrientation(); 0086 } 0087 0088 void CalPainter::paint(int month) 0089 { 0090 if (!device()) 0091 { 0092 return; 0093 } 0094 0095 int width = device()->width(); 0096 int height = device()->height(); 0097 CalSettings* const settings = CalSettings::instance(); 0098 CalParams& params = CalSettings::instance()->params; 0099 0100 // -------------------------------------------------- 0101 0102 // FIXME: magic number 42 0103 0104 int days[42]; 0105 int startDayOffset = QLocale().weekdays().first(); 0106 0107 for (int i = 0 ; i < 42 ; ++i) 0108 { 0109 days[i] = -1; 0110 } 0111 0112 QDate date = CalSystem().date(params.year, month, 1); 0113 int s = date.dayOfWeek(); 0114 0115 if ((s + 7 - startDayOffset) >= 7) 0116 { 0117 s = s - 7; 0118 } 0119 0120 for (int i = s ; i < (s + CalSystem().daysInMonth(date)) ; ++i) 0121 { 0122 days[i + (7 - startDayOffset)] = i - s + 1; 0123 } 0124 0125 // ----------------------------------------------- 0126 0127 QRect rCal(0, 0, 0, 0); 0128 QRect rImage(0, 0, 0, 0); 0129 QRect rCalHeader(0, 0, 0, 0); 0130 0131 int cellSizeX; 0132 int cellSizeY; 0133 0134 switch (params.imgPos) 0135 { 0136 case (CalParams::Top): 0137 { 0138 rImage.setWidth(width); 0139 rImage.setHeight((int)(height * params.ratio / (params.ratio + 100))); 0140 0141 int remainingHeight = height - rImage.height(); 0142 cellSizeX = (width - 20) / 7; 0143 cellSizeY = remainingHeight / 8; 0144 0145 rCal.setWidth(cellSizeX * 7); 0146 rCal.setHeight(cellSizeY * 7); 0147 0148 rCalHeader.setWidth(rCal.width()); 0149 rCalHeader.setHeight(cellSizeY); 0150 rCalHeader.moveTop(rImage.bottom()); 0151 rCalHeader.moveLeft(width / 2 - rCalHeader.width() / 2); 0152 0153 rCal.moveTopLeft(rCalHeader.bottomLeft()); 0154 0155 break; 0156 } 0157 0158 case (CalParams::Left): 0159 { 0160 rImage.setHeight(height); 0161 rImage.setWidth((int)(width * params.ratio / (params.ratio + 100))); 0162 0163 int remainingWidth = width - rImage.width(); 0164 cellSizeX = (remainingWidth - 20) / 8; 0165 cellSizeY = height / 8; 0166 0167 rCal.setWidth(cellSizeX * 7); 0168 rCal.setHeight(cellSizeY * 7); 0169 0170 rCalHeader.setWidth(rCal.width()); 0171 rCalHeader.setHeight(cellSizeY); 0172 rCalHeader.moveLeft(rImage.right() + cellSizeX); 0173 0174 rCal.moveTopLeft(rCalHeader.bottomLeft()); 0175 0176 break; 0177 } 0178 0179 case (CalParams::Right): 0180 { 0181 rImage.setHeight(height); 0182 rImage.setWidth((int)(width * params.ratio / (params.ratio + 100))); 0183 0184 int remainingWidth = width - rImage.width(); 0185 cellSizeX = (remainingWidth - 20) / 8; 0186 cellSizeY = height / 8; 0187 0188 rCal.setWidth(cellSizeX * 7); 0189 rCal.setHeight(cellSizeY * 7); 0190 0191 rCalHeader.setWidth(rCal.width()); 0192 rCalHeader.setHeight(cellSizeY); 0193 rCal.moveTop(rCalHeader.bottom()); 0194 0195 rImage.moveLeft(width - rImage.width()); 0196 0197 break; 0198 } 0199 0200 default: 0201 { 0202 return; 0203 } 0204 } 0205 0206 int fontPixels = cellSizeX / 3; 0207 params.baseFont.setPixelSize(fontPixels); 0208 0209 // --------------------------------------------------------------- 0210 0211 fillRect(0, 0, width, height, Qt::white); 0212 setFont(params.baseFont); 0213 0214 // --------------------------------------------------------------- 0215 0216 save(); 0217 QFont f(params.baseFont); 0218 f.setBold(true); 0219 f.setPixelSize(f.pixelSize() + 5); 0220 setFont(f); 0221 drawText(rCalHeader, Qt::AlignLeft | Qt::AlignVCenter, QString::number(params.year)); 0222 drawText(rCalHeader, Qt::AlignRight | Qt::AlignVCenter, QLocale().standaloneMonthName(month)); 0223 restore(); 0224 0225 // --------------------------------------------------------------- 0226 0227 int sx, sy; 0228 QRect r, rsmall, rSpecial; 0229 0230 r.setWidth(cellSizeX); 0231 r.setHeight(cellSizeY); 0232 0233 int index = 0; 0234 0235 save(); 0236 0237 setPen(Qt::red); 0238 sy = rCal.top(); 0239 0240 for (int i = 0 ; i < 7 ; ++i) 0241 { 0242 int dayname = i + startDayOffset; 0243 0244 if (dayname > 7) 0245 { 0246 dayname = dayname - 7; 0247 } 0248 0249 sx = cellSizeX * i + rCal.left(); 0250 r.moveTopLeft(QPoint(sx, sy)); 0251 rsmall = r; 0252 rsmall.setWidth(r.width() - (r.width() / 10)); 0253 rsmall.setHeight(r.height() - 2); 0254 drawText(rsmall, Qt::AlignRight | Qt::AlignBottom, 0255 QLocale().standaloneDayName(dayname, QLocale::ShortFormat)); 0256 } 0257 0258 restore(); 0259 0260 for (int j = 0 ; j < 6 ; ++j) 0261 { 0262 sy = cellSizeY * (j + 1) + rCal.top(); 0263 0264 for (int i = 0 ; i < 7 ; ++i) 0265 { 0266 sx = cellSizeX * i + rCal.left(); 0267 r.moveTopLeft(QPoint(sx, sy)); 0268 rsmall = r; 0269 rsmall.setWidth(r.width() - (r.width() / 10)); 0270 rsmall.setHeight(r.height() - 2); 0271 0272 if (days[index] != -1) 0273 { 0274 if (settings->isSpecial(month, days[index])) 0275 { 0276 save(); 0277 setPen(settings->getDayColor(month, days[index])); 0278 drawText(rsmall, Qt::AlignRight | Qt::AlignBottom, 0279 QString::number(days[index])); 0280 0281 QString descr = settings->getDayDescr(month, days[index]); 0282 0283 qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Painting special info: '" << descr 0284 << "' for date " << days[index] << "/" 0285 << month; 0286 0287 rSpecial = rsmall; 0288 rSpecial.translate(2, 0); 0289 QFont fnt(params.baseFont); 0290 fnt.setPixelSize(fnt.pixelSize() / 3); 0291 setFont(fnt); 0292 0293 drawText(rSpecial, Qt::AlignLeft | Qt::AlignTop, descr); 0294 0295 restore(); 0296 } 0297 else 0298 { 0299 drawText(rsmall, Qt::AlignRight | Qt::AlignBottom, 0300 QString::number(days[index])); 0301 } 0302 } 0303 0304 index++; 0305 } 0306 } 0307 0308 // --------------------------------------------------------------- 0309 0310 if (params.drawLines) 0311 { 0312 sx = rCal.left(); 0313 0314 for (int j = 0 ; j < 8 ; ++j) 0315 { 0316 sy = cellSizeY * j + rCal.top(); 0317 drawLine(sx, sy, rCal.right(), sy); 0318 } 0319 0320 sy = rCal.top(); 0321 0322 for (int i = 0 ; i < 8 ; ++i) 0323 { 0324 sx = cellSizeX * i + rCal.left(); 0325 drawLine(sx, sy, sx, rCal.bottom()); 0326 } 0327 } 0328 0329 d->image = PreviewLoadThread::loadHighQualitySynchronously(d->imagePath.toLocalFile()).copyQImage(); 0330 0331 if (d->image.isNull()) 0332 { 0333 fillRect(rImage, Qt::blue); 0334 } 0335 else 0336 { 0337 if ( d->orientation != MetaEngine::ORIENTATION_UNSPECIFIED ) 0338 { 0339 QScopedPointer<MetaEngine> meta(new MetaEngine); 0340 meta->rotateExifQImage(d->image, (MetaEngine::ImageOrientation)d->orientation); 0341 } 0342 0343 Q_EMIT signalProgress(0); 0344 0345 d->image = d->image.scaled(rImage.width(), 0346 rImage.height(), 0347 Qt::KeepAspectRatio, 0348 Qt::SmoothTransformation); 0349 0350 Q_EMIT signalTotal(d->image.height()); 0351 0352 int h = d->image.height(); 0353 int x = rImage.bottomLeft().x() + (rImage.width() - d->image.width()) / 2; 0354 int y = (rImage.height() - h) / 2; 0355 int blockSize = 10; 0356 int block = 0; 0357 0358 while ((block < h) && !d->cancelled) 0359 { 0360 if (block + blockSize > h) 0361 { 0362 blockSize = h - block; 0363 } 0364 0365 drawImage(x, y + block, d->image, 0, block, d->image.width(), blockSize); 0366 block += blockSize; 0367 Q_EMIT signalProgress(block); 0368 } 0369 0370 Q_EMIT signalFinished(); 0371 } 0372 } 0373 0374 } // namespace Digikam 0375 0376 #include "moc_calpainter.cpp"