3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
10 // JLH = James L. Hammons <jlhamm@acm.org>
13 // --- ---------- -----------------------------------------------------------
14 // JLH 05/10/2010 Created this file. :-)
15 // JLH 08/28/2010 Restored functionality to library browser
16 // JLH 09/06/2010 Partially fixed thumbnail rendering
22 - Picks up thumbnail directories twice--only once if thumbnail dir doesn't exist
25 #include "librarywidget.h"
27 #include "actionhandler.h"
28 #include "actionlibraryinsert.h"
30 #include "rs_staticgraphicview.h"
31 #include "rs_system.h"
32 #include "paintinterface.h"
34 LibraryWidget::LibraryWidget(QWidget * parent/*= 0*/, Qt::WindowFlags flags/*= 0*/):
35 QWidget(parent, flags), actionHandler(NULL)
38 std::cout << "LibraryWidget::LibraryWidget()" << std::endl;
41 ui.lvDirectory->setColumnCount(1);
43 QStringList directoryList = RS_SYSTEM->getDirectoryList("library");
45 std::cout << "directorySize = " << directoryList.size() << std::endl;
47 for(int i=0; i<directoryList.size(); i++)
48 std::cout << directoryList.at(i).toLocal8Bit().constData() << std::endl;
53 for(QStringList::Iterator it=directoryList.begin(); it!=directoryList.end(); it++)
54 appendTree(NULL, (*it));
57 LibraryWidget::~LibraryWidget()
61 void LibraryWidget::setActionHandler(ActionHandler * ah)
67 * Escape releases focus.
69 void LibraryWidget::keyPressEvent(QKeyEvent * e)
78 QWidget::keyPressEvent(e);
86 void LibraryWidget::insert()
88 QListWidgetItem * item = ui.ivPreview->currentItem();
89 QString dxfPath = getItemPath(item);
91 if (QFileInfo(dxfPath).isReadable())
95 ActionInterface * a = actionHandler->setCurrentAction(RS2::ActionLibraryInsert);
99 ActionLibraryInsert * action = (ActionLibraryInsert *)a;
100 action->setFile(dxfPath);
104 RS_DEBUG->print(RS_Debug::D_ERROR, "LibraryWidget::insert:"
105 "Cannot create action ActionLibraryInsert");
111 RS_DEBUG->print(RS_Debug::D_ERROR,
112 "LibraryWidget::insert: Can't read file: '%s'", dxfPath.toLatin1().data());
117 * Appends the given directory to the given list view item. Called recursively until all
118 * library directories are appended.
120 void LibraryWidget::appendTree(QTreeWidgetItem * item, QString directory)
127 // read subdirectories of this directory:
128 QStringList lDirectoryList = dir.entryList(QDir::Dirs, QDir::Name);
130 for(QStringList::Iterator it=lDirectoryList.begin(); it!=lDirectoryList.end(); it++)
132 if ((*it) != "." && (*it) != "..")
134 // Look for an item already existing and take this instead of
136 QTreeWidgetItem * newItem = NULL;
137 QTreeWidgetItem * searchItem =
138 (item ? item->child(0) : ui.lvDirectory->topLevelItem(0));
142 for(int i=0; i<searchItem->childCount(); i++)
144 if (searchItem->child(i)->text(0) == (*it))
146 newItem = searchItem->child(i);
152 // Create new item if no existing was found:
157 newItem = (item ? new QTreeWidgetItem(item, list) : new QTreeWidgetItem(ui.lvDirectory, list));
160 //This is picking up the directory tree TWICE, but ONLY if there are no thumbnails!
161 //Actually, only if there is no corresponding thumbnail DIRECTORY under .architektonas...
163 //It was picking up .architektonas from the home directory in rs_system.cpp, that's why!
164 //printf("LibraryWidget::appendTree: *it=\"%s\"\n", (*it).toAscii().data());
165 appendTree(newItem, directory + "/" + (*it));
171 * Updates the icon preview.
173 void LibraryWidget::updatePreview(QTreeWidgetItem * item, int /*column*/)
178 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
180 // dir from the point of view of the library browser (e.g. /mechanical/screws)
181 QString directory = getItemDir(item);
182 ui.ivPreview->clear();
184 // List of all directories that contain part libraries:
185 QStringList directoryList = RS_SYSTEM->getDirectoryList("library");
186 QStringList::Iterator it;
188 QStringList itemPathList;
192 // Look in all possible system directories for DXF files in the current library path:
193 for(it=directoryList.begin(); it!=directoryList.end(); ++it)
195 itemDir.setPath((*it) + directory);
197 if (itemDir.exists())
199 QStringList itemNameList = itemDir.entryList(filter, QDir::Files, QDir::Name);
200 QStringList::Iterator it2;
202 for(it2=itemNameList.begin(); it2!=itemNameList.end(); ++it2)
203 itemPathList += itemDir.path() + "/" + (*it2);
210 // Fill items into icon view:
211 QListWidgetItem * newItem;
213 for(it=itemPathList.begin(); it!=itemPathList.end(); ++it)
215 // QString label = QFileInfo(*it).baseName(true);
216 QString label = QFileInfo(*it).completeBaseName();
217 QPixmap pixmap = getPixmap(directory, QFileInfo(*it).fileName(), (*it));
218 // newItem = new QListWidgetItem(ui.ivPreview, label, pixmap);
219 newItem = new QListWidgetItem(QIcon(pixmap), label, ui.ivPreview);
220 //Doesn't do what we want...
221 // newItem->setSizeHint(QSize(64, 64));
222 //printf("LibraryWidget: label = \"%s\"\n", label.toAscii().data());
225 QApplication::restoreOverrideCursor();
229 * @return Directory (in terms of the List view) to the given item (e.g. /mechanical/screws)
230 * (called recursively)
232 QString LibraryWidget::getItemDir(QTreeWidgetItem * item)
237 QTreeWidgetItem * parent = item->parent();
239 return getItemDir(parent) + QString("/%1").arg(item->text(0));
243 * @return Path of the DXF file that is represented by the given item.
245 QString LibraryWidget::getItemPath(QListWidgetItem * item)
247 QString dir = getItemDir(ui.lvDirectory->currentItem());
251 // List of all directories that contain part libraries:
252 QStringList directoryList = RS_SYSTEM->getDirectoryList("library");
253 QStringList::Iterator it;
256 // Look in all possible system directories for DXF files in the current library path:
257 for(it=directoryList.begin(); it!=directoryList.end(); ++it)
259 itemDir.setPath((*it) + dir);
261 if (itemDir.exists())
263 QString f = (*it) + dir + "/" + item->text() + ".dxf";
265 if (QFileInfo(f).isReadable())
275 * @return Pixmap that serves as icon for the given DXF File.
276 * The existing PNG file is returned or created and returned..
278 * @param dir Library directory (e.g. "/mechanical/screws")
279 * @param dxfFile File name (e.g. "screw1.dxf")
280 * @param dxfPath Full path to the existing DXF file on disk
281 * (e.g. /home/tux/.qcad/library/mechanical/screws/screw1.dxf)
283 QPixmap LibraryWidget::getPixmap(const QString & dir, const QString & dxfFile,
284 const QString & dxfPath)
286 QString pngFile = getPathToPixmap(dir, dxfFile, dxfPath);
287 QFileInfo fiPng(pngFile);
289 // Found existing thumbnail:
291 return QPixmap(pngFile);
292 // Default thumbnail:
294 return QPixmap(64, 64);
298 * @return Path to the thumbnail of the given DXF file. If no thumbnail exists, one is
299 * created in the user's home. If no thumbnail can be created, an empty string is returned.
301 QString LibraryWidget::getPathToPixmap(const QString & dir, const QString & dxfFile,
302 const QString & dxfPath)
304 RS_DEBUG->print("LibraryWidget::getPathToPixmap: dir: '%s' dxfFile: '%s' dxfPath: '%s'",
305 dir.toLatin1().data(), dxfFile.toLatin1().data(), dxfPath.toLatin1().data());
307 // List of all directories that contain part libraries:
308 QStringList directoryList = RS_SYSTEM->getDirectoryList("library");
309 directoryList.prepend(RS_SYSTEM->getHomeDir() + "/.architektonas/library");
310 QStringList::Iterator it;
312 QFileInfo fiDxf(dxfPath);
316 // look in all possible system directories for PNG files
317 // in the current library path:
318 for(it=directoryList.begin(); it!=directoryList.end(); ++it)
320 itemDir = (*it) + dir;
321 // pngPath = itemDir + "/" + fiDxf.baseName(true) + ".png";
322 pngPath = itemDir + "/" + fiDxf.completeBaseName() + ".png";
323 RS_DEBUG->print("LibraryWidget::getPathToPixmap: checking: '%s'",
324 pngPath.toLatin1().data());
325 QFileInfo fiPng(pngPath);
327 // the thumbnail exists:
330 RS_DEBUG->print("LibraryWidget::getPathToPixmap: dxf date: %s, png date: %s",
331 fiDxf.lastModified().toString().toLatin1().data(), fiPng.lastModified().toString().toLatin1().data());
333 if (fiPng.lastModified() > fiDxf.lastModified())
335 RS_DEBUG->print("LibraryWidget::getPathToPixmap: thumbnail found: '%s'",
336 pngPath.toLatin1().data());
341 RS_DEBUG->print("LibraryWidget::getPathToPixmap: thumbnail needs to be updated: '%s'",
342 pngPath.toLatin1().data());
347 // The thumbnail must be created in the user's home.
348 // So, create all directories needed:
349 RS_SYSTEM->createHomePath("/.architektonas/library" + dir);
351 QString d = RS_SYSTEM->getHomeDir() + "/.architektonas/library" + dir;
352 //printf("librarywidget: d = \"%s\"\n", d.toAscii().data());
354 // pngPath = d + "/" + fiDxf.baseName(true) + ".png";
355 pngPath = d + "/" + fiDxf.completeBaseName() + ".png";
356 //printf("librarywidget: pngPath = \"%s\"\n", pngPath.toAscii().data());
358 // Ugh. This is a mess and doesn't work right anyway...
359 // Problem is StaticGraphicView doesn't follow a standard rendering path,
360 // so all this crap just ends in failure. Not sure how to fix.
362 I suppose one way to do it would be to make a CreateImage() function in GraphicView,
363 then we wouldn't have all this messiness...
364 I think the way the redraw works is like that--it creates its own PaintInterface
365 and QPainter and sets "painter" equal to it... That being the case, it would be
366 a simple matter to modify StaticGraphicView to utilize that... Let's see...
367 Which it should be doing, but, for some reason, it fails. Dunno why.
369 It only fails for certain DXFs. Dunno why.
372 QPixmap buffer(128, 128);
373 QPainter qpntr(&buffer);
374 PaintInterface * painter = new PaintInterface(&qpntr);
375 qpntr.setBackground(Qt::white);
376 qpntr.eraseRect(0, 0, 128, 128);
378 RS_StaticGraphicView gv(128, 128, painter);
381 if (drawing.open(dxfPath, RS2::FormatUnknown))
383 RS_Color black(0, 0, 0);
385 // Set all pens in the drawing to BLACK
386 for(RS_Entity * e=drawing.firstEntity(RS2::ResolveAll); e!=NULL; e=drawing.nextEntity(RS2::ResolveAll))
388 RS_Pen pen = e->getPen();
393 gv.setContainer(&drawing);
395 //This works, but somehow doesn't work ALL the time
396 gv.drawEntity(&drawing, true);
399 QImage image = buffer.toImage();
400 image.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
401 writer.setFileName(pngPath);
402 writer.setFormat("png");
404 if (!writer.write(image))
406 RS_DEBUG->print(RS_Debug::D_ERROR,
407 "LibraryWidget::getPathToPixmap: Cannot write thumbnail: '%s'",
408 pngPath.toLatin1().data());
414 RS_DEBUG->print(RS_Debug::D_ERROR, "LibraryWidget::getPathToPixmap: Cannot open file: '%s'", dxfPath.toLatin1().data());
424 QWidget::setMinimumSize: (/QMdi::ControlLabel) Negative sizes (-1,-1) are not possible
425 QPaintDevice: Cannot destroy paint device that is being painted
427 Program received signal SIGSEGV, Segmentation fault.
430 #0 0x085cd068 in ?? ()
431 #1 0xb7818bd0 in QPainter::~QPainter() () from /usr/lib/qt4/libQtGui.so.4
432 #2 0x081c1e8e in LibraryWidget::getPathToPixmap(QString const&, QString const&, QString const&) ()
433 #3 0x081c0fa6 in LibraryWidget::getPixmap(QString const&, QString const&, QString const&) ()
434 #4 0x081c0775 in LibraryWidget::updatePreview(QTreeWidgetItem*, int) ()
435 #5 0x08237d5e in LibraryWidget::qt_metacall(QMetaObject::Call, int, void**) ()