1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 /***************************************************************************
8 picstatus.cpp - description
9 -------------------
10 begin : Fri Nov 29 2001
11 copyright : (C) 2001 by Franz Schmid
12 email : Franz.Schmid@altmuehlnet.de
13 ***************************************************************************/
14
15 /***************************************************************************
16 * *
17 * This program is free software; you can redistribute it and/or modify *
18 * it under the terms of the GNU General Public License as published by *
19 * the Free Software Foundation; either version 2 of the License, or *
20 * (at your option) any later version. *
21 * *
22 ***************************************************************************/
23 #include "picstatus.h"
24
25 #include <QAction>
26 #include <QCheckBox>
27 #include <QDesktopServices>
28 #include <QFileInfo>
29 #include <QLabel>
30 #include <QListWidget>
31 #include <QMenu>
32 #include <QMessageBox>
33 #include <QMultiMap>
34 #include <QPainter>
35 #include <QPixmap>
36 #include <QPushButton>
37 #include <QScopedPointer>
38 #include <QToolButton>
39
40 #include "commonstrings.h"
41 #include "effectsdialog.h"
42 #include "extimageprops.h"
43 #include "filesearch.h"
44 #include "iconmanager.h"
45 #include "pageitem.h"
46 #include "picsearch.h"
47 #include "picsearchoptions.h"
48 #include "scribuscore.h"
49 #include "scribusdoc.h"
50 #include "units.h"
51 #include "util_color.h"
52 #include "util_formats.h"
53
54
55
PicItem(QListWidget * parent,const QString & text,const QPixmap & pix,PageItem * pgItem)56 PicItem::PicItem(QListWidget* parent, const QString& text, const QPixmap& pix, PageItem* pgItem)
57 : QListWidgetItem(pix, text, parent)
58 {
59 PageItemObject = pgItem;
60 }
61
PicStatus(QWidget * parent,ScribusDoc * docu)62 PicStatus::PicStatus(QWidget* parent, ScribusDoc *docu) : QDialog( parent )
63 {
64 setupUi(this);
65 setModal(true);
66 imageViewArea->setIconSize(QSize(128, 128));
67 imageViewArea->setContextMenuPolicy(Qt::CustomContextMenu);
68 m_Doc = docu;
69 setWindowIcon(IconManager::instance().loadIcon("AppIcon.png"));
70 fillTable();
71 workTab->setCurrentIndex(0);
72 connect(closeButton, SIGNAL(clicked()), this, SLOT(accept()));
73 connect(imageViewArea, SIGNAL(itemSelectionChanged()), this, SLOT(newImageSelected()));
74 connect(isPrinting, SIGNAL(clicked()), this, SLOT(PrintPic()));
75 connect(isVisibleCheck, SIGNAL(clicked()), this, SLOT(visiblePic()));
76 connect(goPageButton, SIGNAL(clicked()), this, SLOT(GotoPic()));
77 connect(selectButton, SIGNAL(clicked()), this, SLOT(SelectPic()));
78 connect(searchButton, SIGNAL(clicked()), this, SLOT(SearchPic()));
79 connect(fileManagerButton, SIGNAL(clicked()), this, SLOT(FileManager()));
80 connect(effectsButton, SIGNAL(clicked()), this, SLOT(doImageEffects()));
81 connect(buttonLayers, SIGNAL(clicked()), this, SLOT(doImageExtProp()));
82 connect(buttonEdit, SIGNAL(clicked()), this, SLOT(doEditImage()));
83 connect(imageViewArea, SIGNAL(customContextMenuRequested (const QPoint &)), this, SLOT(slotRightClick()));
84 }
85
createImgIcon(PageItem * item)86 QPixmap PicStatus::createImgIcon(PageItem* item)
87 {
88 QPainter p;
89 QPixmap pm(128, 128);
90 QBrush b(QColor(205,205,205), IconManager::instance().loadPixmap("testfill.png"));
91 p.begin(&pm);
92 p.fillRect(0, 0, 128, 128, imageViewArea->palette().window());
93 p.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
94 p.setBrush(palette().window());
95 p.drawRoundedRect(0, 0, 127, 127, 10, 10, Qt::RelativeSize);
96 p.setPen(Qt::NoPen);
97 p.setBrush(b);
98 p.drawRect(12, 12, 104, 104);
99 if (item->imageIsAvailable && QFile::exists(item->externalFile()))
100 {
101 QImage im2 = item->pixm.scaled(104, 104, Qt::KeepAspectRatio, Qt::SmoothTransformation);
102 p.drawImage((104 - im2.width()) / 2 + 12, (104 - im2.height()) / 2 + 12, im2);
103 }
104 else
105 {
106 p.setBrush(Qt::NoBrush);
107 p.setPen(QPen(Qt::red, 2, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
108 p.drawLine(12, 12, 116, 116);
109 p.drawLine(12, 116, 116, 12);
110 }
111 p.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
112 p.setBrush(Qt::NoBrush);
113 p.drawRect(12, 12, 104, 104);
114 p.end();
115 return pm;
116 }
117
enableWidgets(bool enabled)118 void PicStatus::enableWidgets(bool enabled)
119 {
120 isPrinting->setEnabled(enabled);
121 isVisibleCheck->setEnabled(enabled);
122 goPageButton->setEnabled(enabled);
123 selectButton->setEnabled(enabled);
124 searchButton->setEnabled(enabled);
125 fileManagerButton->setEnabled(enabled);
126 effectsButton->setEnabled(enabled);
127 buttonLayers->setEnabled(enabled);
128 buttonEdit->setEnabled(enabled);
129 }
130
fillTable()131 void PicStatus::fillTable()
132 {
133 PageItem *item;
134 imageViewArea->clear();
135 QListWidgetItem *firstItem=nullptr;
136 QListWidgetItem *tempItem=nullptr;
137
138 QList<PageItem*> allItems;
139 for (int i = 0; i < m_Doc->MasterItems.count(); ++i)
140 {
141 PageItem *currItem = m_Doc->MasterItems.at(i);
142 if (currItem->isGroup())
143 allItems = currItem->getAllChildren();
144 else
145 allItems.append(currItem);
146 for (int ii = 0; ii < allItems.count(); ii++)
147 {
148 item = allItems.at(ii);
149 QFileInfo fi = QFileInfo(item->Pfile);
150 QString Iname = "";
151 if (item->isInlineImage)
152 Iname = tr("Embedded Image");
153 else
154 Iname = fi.fileName();
155 if ((item->itemType() == PageItem::ImageFrame) && (!item->isLatexFrame()))
156 tempItem = new PicItem(imageViewArea, Iname, createImgIcon(item), item);
157 if (firstItem == nullptr)
158 firstItem = tempItem;
159 }
160 allItems.clear();
161 }
162 allItems.clear();
163 for (int i = 0; i < m_Doc->DocItems.count(); ++i)
164 {
165 PageItem *currItem = m_Doc->DocItems.at(i);
166 if (currItem->isGroup())
167 allItems = currItem->getAllChildren();
168 else
169 allItems.append(currItem);
170 for (int ii = 0; ii < allItems.count(); ii++)
171 {
172 item = allItems.at(ii);
173 QFileInfo fi = QFileInfo(item->Pfile);
174 QString Iname = "";
175 if (item->isInlineImage)
176 Iname = tr("Embedded Image");
177 else
178 Iname = fi.fileName();
179 if ((item->itemType() == PageItem::ImageFrame) && (!item->isLatexFrame()))
180 tempItem = new PicItem(imageViewArea, Iname, createImgIcon(item), item);
181 // if an image is selected in a doc, Manage Pictures should
182 // display the selected image and its values
183 if (firstItem == nullptr || item->isSelected())
184 firstItem = tempItem;
185 }
186 allItems.clear();
187 }
188 imageViewArea->setCurrentItem(firstItem);
189 if (firstItem!=nullptr)
190 imageSelected(firstItem);
191
192 // Disable all features when there is no image in the document.
193 // It should never be used (see ScribusMainWindow::extrasMenuAboutToShow())
194 // but who knows if it can be configured for shortcut or macro...
195 imageViewArea->setEnabled(imageViewArea->count() > 0);
196 workTab->setEnabled(imageViewArea->count() > 0);
197 sortByName();
198 }
199
sortByName()200 void PicStatus::sortByName()
201 {
202 QMultiMap<QString, PicItem*> sorted;
203
204 int num = imageViewArea->count();
205 if (num == 0)
206 return;
207
208 auto firstItem = imageViewArea->currentItem();
209 for (int i = num - 1; i > -1; --i)
210 {
211 QListWidgetItem *ite = imageViewArea->takeItem(i);
212 PicItem *item = (PicItem*) ite;
213 QFileInfo fi = QFileInfo(item->PageItemObject->Pfile);
214 sorted.insert(fi.fileName(), item);
215 }
216
217 int counter = 0;
218 foreach (const QString& i, sorted.uniqueKeys())
219 {
220 foreach (PicItem* val, sorted.values(i))
221 {
222 imageViewArea->insertItem(counter, val);
223 counter++;
224 }
225 }
226 imageViewArea->setCurrentItem(firstItem);
227 imageSelected(firstItem);
228 sortOrder = 0;
229 }
230
sortByPage()231 void PicStatus::sortByPage()
232 {
233 QMap<int, PicItem*> sorted;
234
235 int num = imageViewArea->count();
236 if (num == 0)
237 return;
238
239 auto firstItem = imageViewArea->currentItem();
240 for (int a = num-1; a > -1; --a)
241 {
242 QListWidgetItem *ite = imageViewArea->takeItem(a);
243 PicItem *item = (PicItem*)ite;
244 sorted.insertMulti(item->PageItemObject->OwnPage, item);
245 }
246 int counter = 0;
247 foreach (int i, sorted.uniqueKeys())
248 {
249 foreach (PicItem* val, sorted.values(i))
250 {
251 imageViewArea->insertItem(counter, val);
252 counter++;
253 }
254 }
255 imageViewArea->setCurrentItem(firstItem);
256 imageSelected(firstItem);
257 sortOrder = 1;
258 }
259
slotRightClick()260 void PicStatus::slotRightClick()
261 {
262 QMenu *pmen = new QMenu();
263 qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
264 QAction* Act1 = pmen->addAction( tr("Sort by Name"));
265 Act1->setCheckable(true);
266 QAction* Act2 = pmen->addAction( tr("Sort by Page"));
267 Act2->setCheckable(true);
268 if (sortOrder == 0)
269 Act1->setChecked(true);
270 else if (sortOrder == 1)
271 Act2->setChecked(true);
272 connect(Act1, SIGNAL(triggered()), this, SLOT(sortByName()));
273 connect(Act2, SIGNAL(triggered()), this, SLOT(sortByPage()));
274 pmen->exec(QCursor::pos());
275 delete pmen;
276 }
277
newImageSelected()278 void PicStatus::newImageSelected()
279 {
280 QList<QListWidgetItem*> items = imageViewArea->selectedItems();
281 imageSelected((items.count() > 0) ? items.at(0) : nullptr);
282 }
283
imageSelected(QListWidgetItem * ite)284 void PicStatus::imageSelected(QListWidgetItem *ite)
285 {
286 if (ite == nullptr)
287 {
288 currItem = nullptr;
289 enableWidgets(false);
290 return;
291 }
292
293 enableWidgets(true);
294
295 PicItem *item = (PicItem*) ite;
296 currItem = item->PageItemObject;
297 if (!currItem->OnMasterPage.isEmpty())
298 displayPage->setText(currItem->OnMasterPage);
299 else
300 {
301 if (currItem->OwnPage == -1)
302 displayPage->setText( tr("Not on a Page"));
303 else
304 displayPage->setText(QString::number(currItem->OwnPage + 1));
305 }
306 displayObjekt->setText(currItem->itemName());
307 if (currItem->imageIsAvailable)
308 {
309 QFileInfo fi = QFileInfo(currItem->Pfile);
310 QString ext = fi.suffix().toLower();
311 if (currItem->isInlineImage)
312 {
313 displayName->setText( tr("Embedded Image"));
314 displayPath->setText("");
315 searchButton->setEnabled(false);
316 fileManagerButton->setEnabled(false);
317 }
318 else
319 {
320 displayName->setText(fi.fileName());
321 displayPath->setText(QDir::toNativeSeparators(fi.path()));
322 searchButton->setEnabled(true);
323 fileManagerButton->setEnabled(true);
324 }
325 QString format = "";
326 switch (currItem->pixm.imgInfo.type)
327 {
328 case 0:
329 format = tr("JPG");
330 break;
331 case 1:
332 format = tr("TIFF");
333 break;
334 case 2:
335 format = tr("PSD");
336 break;
337 case 3:
338 format = tr("EPS/PS");
339 break;
340 case 4:
341 format = tr("PDF");
342 break;
343 case 5:
344 format = tr("JPG2000");
345 break;
346 case 6:
347 format = ext.toUpper();
348 break;
349 case 7:
350 format = tr("emb. PSD");
351 break;
352 }
353 displayFormat->setText(format);
354 QString cSpace;
355 if ((extensionIndicatesPDF(ext) || extensionIndicatesEPSorPS(ext)) && (currItem->pixm.imgInfo.type != ImageType7))
356 cSpace = tr("Unknown");
357 else
358 cSpace=colorSpaceText(currItem->pixm.imgInfo.colorspace);
359 displayColorspace->setText(cSpace);
360 displayDPI->setText(QString("%1 x %2").arg(currItem->pixm.imgInfo.xres).arg(currItem->pixm.imgInfo.yres));
361 displayEffDPI->setText(QString("%1 x %2").arg(qRound(72.0 / currItem->imageXScale())).arg(qRound(72.0 / currItem->imageYScale())));
362 displaySizePixel->setText(QString("%1 x %2").arg(currItem->OrigW).arg(currItem->OrigH));
363 displayScale->setText(QString("%1 x %2 %").arg(currItem->imageXScale() * 100 / 72.0 * currItem->pixm.imgInfo.xres, 5, 'f', 1).arg(currItem->imageYScale() * 100 / 72.0 * currItem->pixm.imgInfo.yres, 5, 'f', 1));
364 displayPrintSize->setText(QString("%1 x %2%3").arg(currItem->OrigW * currItem->imageXScale() * m_Doc->unitRatio(), 7, 'f', 2).arg(currItem->OrigH * currItem->imageXScale() * m_Doc->unitRatio(), 7, 'f', 2).arg(unitGetSuffixFromIndex(m_Doc->unitIndex())));
365 isPrinting->setChecked(currItem->printEnabled());
366 isVisibleCheck->setChecked(currItem->imageVisible());
367 buttonEdit->setEnabled(currItem->isRaster);
368 effectsButton->setEnabled(currItem->isRaster);
369 buttonLayers->setEnabled(currItem->pixm.imgInfo.valid);
370 }
371 else
372 {
373 QString trNA = tr("n/a");
374 if (!currItem->Pfile.isEmpty())
375 {
376 QFileInfo fi = QFileInfo(currItem->Pfile);
377 displayName->setText(fi.fileName());
378 displayPath->setText(QDir::toNativeSeparators(fi.path()));
379 searchButton->setEnabled(true);
380 fileManagerButton->setEnabled(true);
381 }
382 else
383 {
384 displayName->setText(trNA);
385 displayPath->setText(trNA);
386 searchButton->setEnabled(false);
387 fileManagerButton->setEnabled(false);
388 }
389 displayFormat->setText(trNA);
390 displayColorspace->setText(trNA);
391 displayDPI->setText(trNA);
392 displayEffDPI->setText(trNA);
393 displaySizePixel->setText(trNA);
394 displayScale->setText(trNA);
395 displayPrintSize->setText(trNA);
396 buttonEdit->setEnabled(false);
397 effectsButton->setEnabled(false);
398 buttonLayers->setEnabled(false);
399 }
400 }
401
PrintPic()402 void PicStatus::PrintPic()
403 {
404 if (currItem != nullptr)
405 currItem->setPrintEnabled(isPrinting->isChecked());
406 }
407
visiblePic()408 void PicStatus::visiblePic()
409 {
410 if (currItem == nullptr)
411 return;
412 currItem->setImageVisible(isVisibleCheck->isChecked());
413 }
414
GotoPic()415 void PicStatus::GotoPic()
416 {
417 if (currItem == nullptr)
418 return;
419
420 if (currItem->OnMasterPage.isEmpty() && m_Doc->masterPageMode())
421 ScCore->primaryMainWindow()->closeActiveWindowMasterPageEditor();
422 if (!currItem->OnMasterPage.isEmpty())
423 emit selectMasterPage(currItem->OnMasterPage);
424 else
425 emit selectPage(currItem->OwnPage);
426
427 emit selectElementByItem(currItem, true, 1);
428 }
429
SelectPic()430 void PicStatus::SelectPic()
431 {
432 if (currItem == nullptr)
433 return;
434
435 if (currItem->OnMasterPage.isEmpty() && m_Doc->masterPageMode())
436 ScCore->primaryMainWindow()->closeActiveWindowMasterPageEditor();
437 else
438 if (!currItem->OnMasterPage.isEmpty() && !m_Doc->masterPageMode())
439 emit selectMasterPage(currItem->OnMasterPage);
440
441 emit selectElementByItem(currItem, true, 1);
442 }
443
loadPict(PageItem * item,const QString & newFilePath)444 bool PicStatus::loadPict(PageItem* item, const QString & newFilePath)
445 {
446 // Hack to fool the LoadPict function
447 item->Pfile = newFilePath;
448 bool masterPageMode = !item->OnMasterPage.isEmpty();
449 bool oldMasterPageMode = m_Doc->masterPageMode();
450 if (masterPageMode != oldMasterPageMode)
451 m_Doc->setMasterPageMode(masterPageMode);
452 m_Doc->loadPict(newFilePath, item, true);
453 if (masterPageMode != oldMasterPageMode)
454 m_Doc->setMasterPageMode(oldMasterPageMode);
455 return item->imageIsAvailable;
456 }
457
SearchPic()458 void PicStatus::SearchPic()
459 {
460 // no action where is no item selected. It should never happen.
461 if (currItem == nullptr)
462 return;
463 static QString lastSearchPath;
464
465 if (lastSearchPath.isEmpty())
466 lastSearchPath = displayPath->text();
467
468 QScopedPointer<PicSearchOptions> dia(new PicSearchOptions(this, displayName->text(), lastSearchPath));
469 if (dia->exec() != QDialog::Accepted)
470 return;
471
472 lastSearchPath = dia->getLastDirSearched();
473 if (dia->getMatches().count() == 0)
474 {
475 ScMessageBox::information(this, tr("Scribus - Image Search"), tr("No images named \"%1\" were found.").arg(dia->getFileName()),
476 QMessageBox::Ok|QMessageBox::Default|QMessageBox::Escape,
477 QMessageBox::NoButton);
478 return;
479 }
480
481 auto item = static_cast<PicItem*>(imageViewArea->currentItem());
482 bool brokenLink = !(item->PageItemObject->imageIsAvailable);
483
484 QScopedPointer<PicSearch> dia2(new PicSearch(this, dia->getFileName(), dia->getMatches(), brokenLink));
485 if (dia2->exec() != QDialog::Accepted)
486 return;
487
488 auto source = QFileInfo(currItem->Pfile);
489
490 loadPict(currItem, dia2->getSelectedImage());
491 auto target = QFileInfo(currItem->Pfile);
492 item->setText(target.fileName());
493 item->setIcon(createImgIcon(currItem));
494 imageSelected(imageViewArea->currentItem());
495
496 if (dia2->isApplyToMatchingImages())
497 relinkMatchingImages(source, target, brokenLink);
498 }
499
FileManager()500 void PicStatus::FileManager()
501 {
502 if (currItem == nullptr)
503 return;
504 QFileInfo fi = QFileInfo(currItem->Pfile);
505 QString path = fi.canonicalPath();
506 if (path.isEmpty())
507 return;
508 QDesktopServices::openUrl(QUrl::fromLocalFile(path));
509 }
510
doImageEffects()511 void PicStatus::doImageEffects()
512 {
513 if (currItem == nullptr)
514 return;
515
516 EffectsDialog* dia = new EffectsDialog(this, currItem, m_Doc);
517 if (dia->exec())
518 {
519 currItem->effectsInUse = dia->effectsList;
520 loadPict(currItem, currItem->Pfile);
521 imageViewArea->currentItem()->setIcon(createImgIcon(currItem));
522 }
523 delete dia;
524 }
525
doImageExtProp()526 void PicStatus::doImageExtProp()
527 {
528 if (currItem == nullptr)
529 return;
530
531 ExtImageProps dia(this, &currItem->pixm.imgInfo, currItem, m_Doc->view());
532 if (dia.exec())
533 {
534 loadPict(currItem, currItem->Pfile);
535 imageViewArea->currentItem()->setIcon(createImgIcon(currItem));
536 }
537 }
538
doEditImage()539 void PicStatus::doEditImage()
540 {
541 if (currItem == nullptr)
542 return;
543 SelectPic();
544 ScCore->primaryMainWindow()->callImageEditor();
545 }
546
547 /**
548 * Relink all matching images.
549 * Images match if they have the same path as the pattern.
550 * If the "pattern" was a broken link, only images with broken links will match.
551 */
relinkMatchingImages(const QFileInfo & source,const QFileInfo & target,bool brokenLink)552 void PicStatus::relinkMatchingImages(const QFileInfo& source, const QFileInfo& target, bool brokenLink)
553 {
554 for (int i = 0; i < imageViewArea->count(); i++)
555 {
556 auto item = static_cast<PicItem*>(imageViewArea->item(i));
557
558 if (brokenLink && item->PageItemObject->imageIsAvailable)
559 continue;
560
561 auto fi = QFileInfo(item->PageItemObject->Pfile);
562
563 if (fi.path() != source.path())
564 continue;
565 if (fi.fileName() == target.fileName())
566 continue;
567
568 loadPict(item->PageItemObject, QDir(target.path()).filePath(fi.fileName()));
569 item->setText(fi.fileName());
570 item->setIcon(createImgIcon(item->PageItemObject));
571 }
572 }
573