]> Shamusworld >> Repos - architektonas/blob - src/forms/librarywidget.cpp
Bugfixes related to removing Snapper class.
[architektonas] / src / forms / librarywidget.cpp
1 // librarywidget.cpp
2 //
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
9 //
10 // JLH = James L. Hammons <jlhamm@acm.org>
11 //
12 // Who  When        What
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
17 // JLH  09/07/2010  Fully fixed thumbnail rendering
18 //
19
20 /*
21 Note that this is basically just a way to get a block from a file; it's unclear
22 that it does so and the doco (such as it was) didn't mention it either. So what
23 we need is to make it very clear that inserting is to the BLOCK list and not
24 the document--perhaps we need to fold it into the block list, and make the
25 insert function insert into the block list only...
26 Also, it would be useful to have some information like base unit, dimensions, etc.
27 */
28
29 #include "librarywidget.h"
30
31 #include "actionhandler.h"
32 #include "actionlibraryinsert.h"
33 #include "drawing.h"
34 #include "staticgraphicview.h"
35 #include "system.h"
36 #include "paintinterface.h"
37
38 LibraryWidget::LibraryWidget(QWidget * parent/*= 0*/, Qt::WindowFlags flags/*= 0*/):
39         QWidget(parent, flags), actionHandler(NULL)
40 {
41 #if 0
42 std::cout << "LibraryWidget::LibraryWidget()" << std::endl;
43 #endif
44         ui.setupUi(this);
45         ui.lvDirectory->setColumnCount(1);
46
47         QStringList directoryList = SYSTEM->getDirectoryList("library");
48 #if 0
49 std::cout << "directorySize = " << directoryList.size() << std::endl;
50
51 for(int i=0; i<directoryList.size(); i++)
52         std::cout << directoryList.at(i).toLocal8Bit().constData() << std::endl;
53
54 std::cout.flush();
55 #endif
56
57         for(QStringList::Iterator it=directoryList.begin(); it!=directoryList.end(); it++)
58                 appendTree(NULL, (*it));
59 }
60
61 LibraryWidget::~LibraryWidget()
62 {
63 }
64
65 void LibraryWidget::setActionHandler(ActionHandler * ah)
66 {
67         actionHandler = ah;
68 }
69
70 /**
71  * Escape releases focus.
72  */
73 void LibraryWidget::keyPressEvent(QKeyEvent * e)
74 {
75         switch (e->key())
76         {
77         case Qt::Key_Escape:
78                 emit escape();
79                 break;
80
81         default:
82                 QWidget::keyPressEvent(e);
83                 break;
84         }
85 }
86
87 /**
88  * Insert.
89  */
90 void LibraryWidget::insert()
91 {
92         QListWidgetItem * item = ui.ivPreview->currentItem();
93         QString dxfPath = getItemPath(item);
94
95         if (QFileInfo(dxfPath).isReadable())
96         {
97                 if (actionHandler)
98                 {
99                         ActionInterface * a = actionHandler->setCurrentAction(RS2::ActionLibraryInsert);
100
101                         if (a)
102                         {
103                                 ActionLibraryInsert * action = (ActionLibraryInsert *)a;
104                                 action->setFile(dxfPath);
105                         }
106                         else
107                         {
108                                 DEBUG->print(Debug::D_ERROR, "LibraryWidget::insert:"
109                                         "Cannot create action ActionLibraryInsert");
110                         }
111                 }
112         }
113         else
114         {
115                 DEBUG->print(Debug::D_ERROR,
116                         "LibraryWidget::insert: Can't read file: '%s'", dxfPath.toLatin1().data());
117         }
118 }
119
120 /**
121  * Appends the given directory to the given list view item. Called recursively until all
122  * library directories are appended.
123  */
124 void LibraryWidget::appendTree(QTreeWidgetItem * item, QString directory)
125 {
126         QDir dir(directory);
127
128         if (!dir.exists())
129                 return;
130
131         // read subdirectories of this directory:
132         QStringList lDirectoryList = dir.entryList(QDir::Dirs, QDir::Name);
133
134         for(QStringList::Iterator it=lDirectoryList.begin(); it!=lDirectoryList.end(); it++)
135         {
136                 if ((*it) != "." && (*it) != "..")
137                 {
138                         // Look for an item already existing and take this instead of
139                         // making a new one:
140                         QTreeWidgetItem * newItem = NULL;
141                         QTreeWidgetItem * searchItem =
142                                 (item ? item->child(0) : ui.lvDirectory->topLevelItem(0));
143
144                         if (searchItem)
145                         {
146                                 for(int i=0; i<searchItem->childCount(); i++)
147                                 {
148                                         if (searchItem->child(i)->text(0) == (*it))
149                                         {
150                                                 newItem = searchItem->child(i);
151                                                 break;
152                                         }
153                                 }
154                         }
155
156                         // Create new item if no existing was found:
157                         if (!newItem)
158                         {
159                                 QStringList list;
160                                 list << (*it);
161                                 newItem = (item ? new QTreeWidgetItem(item, list) : new QTreeWidgetItem(ui.lvDirectory, list));
162                         }
163
164 //This is picking up the directory tree TWICE, but ONLY if there are no thumbnails!
165 //Actually, only if there is no corresponding thumbnail DIRECTORY under .architektonas...
166 //Dunno why...
167 //It was picking up .architektonas from the home directory in rs_system.cpp, that's why!
168 //printf("LibraryWidget::appendTree: *it=\"%s\"\n", (*it).toAscii().data());
169                         appendTree(newItem, directory + "/" + (*it));
170                 }
171         }
172 }
173
174 /**
175  * Updates the icon preview.
176  */
177 void LibraryWidget::updatePreview(QTreeWidgetItem * item, int /*column*/)
178 {
179         if (!item)
180                 return;
181
182         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
183
184         // dir from the point of view of the library browser (e.g. /mechanical/screws)
185         QString directory = getItemDir(item);
186         ui.ivPreview->clear();
187
188         // List of all directories that contain part libraries:
189         QStringList directoryList = SYSTEM->getDirectoryList("library");
190         QStringList::Iterator it;
191         QDir itemDir;
192         QStringList itemPathList;
193         QStringList filter;
194         filter << "*.dxf";
195
196         // Look in all possible system directories for DXF files in the current library path:
197         for(it=directoryList.begin(); it!=directoryList.end(); ++it)
198         {
199                 itemDir.setPath((*it) + directory);
200
201                 if (itemDir.exists())
202                 {
203                         QStringList itemNameList = itemDir.entryList(filter, QDir::Files, QDir::Name);
204                         QStringList::Iterator it2;
205
206                         for(it2=itemNameList.begin(); it2!=itemNameList.end(); ++it2)
207                                 itemPathList += itemDir.path() + "/" + (*it2);
208                 }
209         }
210
211         // Sort entries:
212         itemPathList.sort();
213
214         // Fill items into icon view:
215         QListWidgetItem * newItem;
216
217         for(it=itemPathList.begin(); it!=itemPathList.end(); ++it)
218         {
219 //              QString label = QFileInfo(*it).baseName(true);
220                 QString label = QFileInfo(*it).completeBaseName();
221                 QPixmap pixmap = getPixmap(directory, QFileInfo(*it).fileName(), (*it));
222 //              newItem = new QListWidgetItem(ui.ivPreview, label, pixmap);
223                 newItem = new QListWidgetItem(QIcon(pixmap), label, ui.ivPreview);
224 //Doesn't do what we want...
225 //              newItem->setSizeHint(QSize(64, 64));
226 //printf("LibraryWidget: label = \"%s\"\n", label.toAscii().data());
227         }
228
229         QApplication::restoreOverrideCursor();
230 }
231
232 /**
233  * @return Directory (in terms of the List view) to the given item (e.g. /mechanical/screws)
234  * (called recursively)
235  */
236 QString LibraryWidget::getItemDir(QTreeWidgetItem * item)
237 {
238         if (!item)
239                 return "";
240
241         QTreeWidgetItem * parent = item->parent();
242
243         return getItemDir(parent) + QString("/%1").arg(item->text(0));
244 }
245
246 /**
247  * @return Path of the DXF file that is represented by the given item.
248  */
249 QString LibraryWidget::getItemPath(QListWidgetItem * item)
250 {
251         QString dir = getItemDir(ui.lvDirectory->currentItem());
252
253         if (item)
254         {
255                 // List of all directories that contain part libraries:
256                 QStringList directoryList = SYSTEM->getDirectoryList("library");
257                 QStringList::Iterator it;
258                 QDir itemDir;
259
260                 // Look in all possible system directories for DXF files in the current library path:
261                 for(it=directoryList.begin(); it!=directoryList.end(); ++it)
262                 {
263                         itemDir.setPath((*it) + dir);
264
265                         if (itemDir.exists())
266                         {
267                                 QString f = (*it) + dir + "/" + item->text() + ".dxf";
268
269                                 if (QFileInfo(f).isReadable())
270                                         return f;
271                         }
272                 }
273         }
274
275         return "";
276 }
277
278 /**
279  * @return Pixmap that serves as icon for the given DXF File.
280  * The existing PNG file is returned or created and returned..
281  *
282  * @param dir Library directory (e.g. "/mechanical/screws")
283  * @param dxfFile File name (e.g. "screw1.dxf")
284  * @param dxfPath Full path to the existing DXF file on disk
285  *                (e.g. /home/tux/.architektonas/library/mechanical/screws/screw1.dxf)
286  */
287 QPixmap LibraryWidget::getPixmap(const QString & dir, const QString & dxfFile,
288         const QString & dxfPath)
289 {
290         QString pngFile = getPathToPixmap(dir, dxfFile, dxfPath);
291         QFileInfo fiPng(pngFile);
292
293         // Found existing thumbnail:
294         if (fiPng.isFile())
295                 return QPixmap(pngFile);
296         // Default thumbnail:
297         else
298                 return QPixmap(64, 64);
299 }
300
301 /**
302  * @return Path to the thumbnail of the given DXF file. If no thumbnail exists, one is
303  * created in the user's home. If no thumbnail can be created, an empty string is returned.
304  */
305 QString LibraryWidget::getPathToPixmap(const QString & dir, const QString & dxfFile,
306         const QString & dxfPath)
307 {
308         DEBUG->print("LibraryWidget::getPathToPixmap: dir: '%s' dxfFile: '%s' dxfPath: '%s'",
309                 dir.toLatin1().data(), dxfFile.toLatin1().data(), dxfPath.toLatin1().data());
310
311         // List of all directories that contain part libraries:
312         QStringList directoryList = SYSTEM->getDirectoryList("library");
313         directoryList.prepend(SYSTEM->getHomeDir() + "/.architektonas/library");
314         QStringList::Iterator it;
315
316         QFileInfo fiDxf(dxfPath);
317         QString itemDir;
318         QString pngPath;
319
320         // look in all possible system directories for PNG files
321         //  in the current library path:
322         for(it=directoryList.begin(); it!=directoryList.end(); ++it)
323         {
324                 itemDir = (*it) + dir;
325                 pngPath = itemDir + "/" + fiDxf.completeBaseName() + ".png";
326                 DEBUG->print("LibraryWidget::getPathToPixmap: checking: '%s'",
327                         pngPath.toLatin1().data());
328                 QFileInfo fiPng(pngPath);
329
330                 // the thumbnail exists:
331                 if (fiPng.isFile())
332                 {
333                         DEBUG->print("LibraryWidget::getPathToPixmap: dxf date: %s, png date: %s",
334                                 fiDxf.lastModified().toString().toLatin1().data(), fiPng.lastModified().toString().toLatin1().data());
335
336                         if (fiPng.lastModified() > fiDxf.lastModified())
337                         {
338                                 DEBUG->print("LibraryWidget::getPathToPixmap: thumbnail found: '%s'",
339                                         pngPath.toLatin1().data());
340                                 return pngPath;
341                         }
342                         else
343                         {
344                                 DEBUG->print("LibraryWidget::getPathToPixmap: thumbnail needs to be updated: '%s'",
345                                         pngPath.toLatin1().data());
346                         }
347                 }
348         }
349
350         // The thumbnail must be created in the user's home.
351         // So, create all directories needed:
352         SYSTEM->createHomePath("/.architektonas/library" + dir);
353         QString d = SYSTEM->getHomeDir() + "/.architektonas/library" + dir;
354         pngPath = d + "/" + fiDxf.completeBaseName() + ".png";
355
356         QPixmap buffer(128, 128);
357         QPainter qpntr(&buffer);
358         PaintInterface * painter = new PaintInterface(&qpntr);
359         qpntr.setBackground(Qt::white);
360         qpntr.eraseRect(0, 0, 128, 128);
361
362         StaticGraphicView view(128, 128, painter);
363         Drawing drawing;
364
365         if (drawing.open(dxfPath, RS2::FormatUnknown))
366         {
367                 Color black(0, 0, 0);
368
369                 // Set all pens in the drawing to BLACK
370                 for(Entity * e=drawing.firstEntity(RS2::ResolveAll); e!=NULL; e=drawing.nextEntity(RS2::ResolveAll))
371                 {
372                         Pen pen = e->getPen();
373                         pen.setColor(black);
374                         e->setPen(pen);
375                 }
376
377                 view.setContainer(&drawing);
378                 view.zoomAuto(false);
379                 view.drawEntity(&drawing, true);
380
381                 QImageWriter writer;
382                 QImage image = buffer.toImage();
383                 image.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
384                 writer.setFileName(pngPath);
385                 writer.setFormat("png");
386
387                 if (!writer.write(image))
388                 {
389                         DEBUG->print(Debug::D_ERROR,
390                                 "LibraryWidget::getPathToPixmap: Cannot write thumbnail: '%s'",
391                                 pngPath.toLatin1().data());
392                         pngPath = "";
393                 }
394         }
395         else
396         {
397                 DEBUG->print(Debug::D_ERROR, "LibraryWidget::getPathToPixmap: Cannot open file: '%s'", dxfPath.toLatin1().data());
398         }
399
400         delete painter;
401
402         return pngPath;
403 }