Files
newspark110/ui/qg_librarywidget.cpp
Chenwenxuan edac2715f0 init
2024-03-06 14:54:30 +08:00

498 lines
16 KiB
C++

/****************************************************************************
**
** This file is part of the LibreCAD project, a 2D CAD program
**
** Copyright (C) 2011 Rallaz (rallazz@gmail.com)
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
**
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file gpl-2.0.txt included in the
** packaging of this file.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**
** This copyright notice MUST APPEAR in all copies of the script!
**
**********************************************************************/
#include "qg_librarywidget.h"
#include <QVBoxLayout>
#include <QTreeView>
#include <QListView>
#include <QPushButton>
#include <QStandardItemModel>
#include <QDesktopServices>
#include <QApplication>
#include <QDateTime>
#include <QImageWriter>
#include <QMouseEvent>
#include "rs_system.h"
#include "rs_settings.h"
#include "rs_painterqt.h"
#include "rs_staticgraphicview.h"
#include "rs_actionlibraryinsert.h"
#include "qg_actionhandler.h"
#include "rs_debug.h"
/*
* Constructs a QG_LibraryWidget as a child of 'parent', with the
* name 'name' and widget flags set to 'f'.
*
* @author Rallaz
*/
QG_LibraryWidget::QG_LibraryWidget(QWidget* parent, const char* name, Qt::WindowFlags fl)
: QWidget(parent, fl)
{
setObjectName(name);
actionHandler = nullptr;
QVBoxLayout *vboxLayout = new QVBoxLayout(this);
vboxLayout->setSpacing(2);
vboxLayout->setContentsMargins(2, 2, 2, 2);
dirView = new QTreeView(this);
dirView->setRootIsDecorated(true);
dirView->setEditTriggers(QAbstractItemView::NoEditTriggers);
vboxLayout->addWidget(dirView);
ivPreview = new QListView(this);
ivPreview->setViewMode(QListView::IconMode);
vboxLayout->addWidget(ivPreview);
bInsert = new QPushButton(tr("Insert"), this);
vboxLayout->addWidget(bInsert);
QHBoxLayout *refreshButtonsLayout = new QHBoxLayout(this);
bRefresh = new QPushButton(tr("Refresh"), this);
refreshButtonsLayout->addWidget(bRefresh);
bRebuild = new QPushButton(tr("Rebuild"), this);
refreshButtonsLayout->addWidget(bRebuild);
vboxLayout->addLayout(refreshButtonsLayout);
buildTree();
connect(dirView, SIGNAL(expanded(QModelIndex)), this, SLOT(expandView(QModelIndex)));
connect(dirView, SIGNAL(collapsed(QModelIndex)), this, SLOT(collapseView(QModelIndex)));
connect(dirView, SIGNAL(clicked(QModelIndex)), this, SLOT(updatePreview(QModelIndex)));
connect(bInsert, SIGNAL(clicked()), this, SLOT(insert()));
connect(bRefresh, SIGNAL(clicked()), this, SLOT(refresh()));
connect(bRebuild, SIGNAL(clicked()), this, SLOT(buildTree()));
}
/*
* Destroys the object and frees any allocated resources
*
* @author Rallaz
*/
QG_LibraryWidget::~QG_LibraryWidget()
{
// no need to delete child widgets, Qt does it all for us
// delete model; //??????
/* QStandardItemModel *model;
QTreeView *dirView;
QListView *ivPreview;*/
}
/*
* Sets the strings of the subwidgets using the current
* language.
* @author Rallaz
*/
void QG_LibraryWidget::languageChange()
{
// retranslateUi(this);
}
void QG_LibraryWidget::setActionHandler(QG_ActionHandler* ah) {
actionHandler = ah;
}
/**
* Escape releases focus.
*/
void QG_LibraryWidget::keyPressEvent(QKeyEvent* e) {
switch (e->key()) {
case Qt::Key_Escape:
emit escape();
break;
default:
QWidget::keyPressEvent(e);
break;
}
}
/**
* Insert.
*/
void QG_LibraryWidget::insert() {
QItemSelectionModel* selIconView = ivPreview->selectionModel();
QModelIndex idx = selIconView->currentIndex();
QStandardItem * item = iconModel->itemFromIndex ( idx );
if (item == 0)
return;
QString dxfPath = getItemPath(item);
if (QFileInfo(dxfPath).isReadable()) {
if (actionHandler) {
RS_ActionInterface* a =
actionHandler->setCurrentAction(RS2::ActionLibraryInsert);
if (a) {
RS_ActionLibraryInsert* action = (RS_ActionLibraryInsert*)a;
action->setFile(dxfPath);
} else {
RS_DEBUG->print(RS_Debug::D_ERROR,
"QG_LibraryWidget::insert:"
"Cannot create action RS_ActionLibraryInsert");
}
}
} else {
RS_DEBUG->print(RS_Debug::D_ERROR,
"QG_LibraryWidget::insert: Can't read file: '%s'", dxfPath.toLatin1().data());
}
}
/**
* Refresh
*/
void QG_LibraryWidget::refresh() {
scanTree();
updatePreview(dirView->selectionModel()->currentIndex());
}
/**
* Scan library tree for new items
*/
void QG_LibraryWidget::scanTree() {
QStringList directoryList = RS_SYSTEM->getDirectoryList("library");
for (int i = 0; i < directoryList.size(); ++i) {
appendTree(nullptr, directoryList.at(i));
}
RS_SETTINGS->beginGroup("/Paths");
QString customPath=RS_SETTINGS->readEntry("/Library", "");
RS_SETTINGS->endGroup();
if(customPath.size()>0){
//todo: make the custom path more flexible
appendTree(nullptr,customPath);
}
}
/**
* (Re)build dirModel and iconModel from scratch
*/
void QG_LibraryWidget::buildTree() {
if (dirModel)
delete dirModel;
if (iconModel)
delete iconModel;
dirModel = new QStandardItemModel;
iconModel = new QStandardItemModel;
scanTree();
dirView->setModel(dirModel);
ivPreview->setModel(iconModel);
dirModel->setHorizontalHeaderLabels ( QStringList(tr("Directories")));
}
/**
* Appends the given directory to the given list view item. Called recursively until all
* library directories are appended.
*
* @author Rallaz
*/
void QG_LibraryWidget::appendTree(QStandardItem* item, QString directory) {
// QStringList::Iterator it;
QDir dir(directory);
if (!dir.exists()) return;
// read subdirectories of this directory:
QStringList lDirectoryList = dir.entryList(QDir::Dirs|QDir::NoDotAndDotDot, QDir::Name);
if (!item) item = dirModel->invisibleRootItem();
for (int i = 0; i < lDirectoryList.size(); ++i) {
QStandardItem* newItem=nullptr;
// Look for an item already existing and take this
// instead of making a new one:
for (int j = 0; j < item->rowCount(); ++j) {
QStandardItem* const searchItem = item->child (j);
if (searchItem->text() == lDirectoryList.at(i)) {
newItem=searchItem;
break;
}
}
// Create new item if no existing was found:
if (!newItem) {
newItem = new QStandardItem(QIcon(":/ui/folderclosed.png"), lDirectoryList.at(i));
item->setChild(item->rowCount(), newItem);
}
appendTree(newItem, directory+QDir::separator()+lDirectoryList.at(i));
}
item->sortChildren ( 0, Qt::AscendingOrder );
}
/**
* Change the icon item when is expanded.
*
* @author Rallaz
*/
void QG_LibraryWidget::expandView( QModelIndex idx ){
QStandardItem * item = dirModel->itemFromIndex ( idx );
if (item != 0)
item->setIcon(QIcon(":/ui/folderopen.png"));
}
/**
* Change the icon item when is collapsed.
*
* @author Rallaz
*/
void QG_LibraryWidget::collapseView( QModelIndex idx ){
QStandardItem * item = dirModel->itemFromIndex ( idx );
if (item != 0)
item->setIcon(QIcon(":/ui/folderclosed.png"));
}
/**
* Updates the icon preview.
*
* @author Rallaz
*/
void QG_LibraryWidget::updatePreview(QModelIndex idx) {
QStandardItem * item = dirModel->itemFromIndex ( idx );
if (item == 0)
return;
QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
// dir from the point of view of the library browser (e.g. /mechanical/screws)
QString directory = getItemDir(item); //RLZ change to do-while
iconModel->clear();
// List of all directories that contain part libraries:
QStringList directoryList = RS_SYSTEM->getDirectoryList("library");
QDir itemDir;
QStringList itemPathList;
// look in all possible system directories for DXF files in the current library path:
for (int i = 0; i < directoryList.size(); ++i) {
itemDir.setPath(directoryList.at(i)+directory);
if (itemDir.exists()) {
QStringList itemNameList =
itemDir.entryList(QStringList("*.dxf"), QDir::Files, QDir::Name);
for (int j = 0; j < itemNameList.size(); ++j) {
itemPathList += itemDir.path()+QDir::separator()+itemNameList.at(j);
}
}
}
// Sort entries:
itemPathList.sort();
// Fill items into icon view:
QStandardItem* newItem;
for (int i = 0; i < itemPathList.size(); ++i) {
QString label = QFileInfo(itemPathList.at(i)).completeBaseName();
QIcon icon = getIcon(directory, QFileInfo(itemPathList.at(i)).fileName(), itemPathList.at(i));
newItem = new QStandardItem(icon, label);
iconModel->setItem(i, newItem);
}
QApplication::restoreOverrideCursor();
}
//RLZ change to do-while
/**
* @return Directory (in terms of the List view) to the given item (e.g. /mechanical/screws)
*/
QString QG_LibraryWidget::getItemDir(QStandardItem* item) {
if (!item) return QString();
QStandardItem* parent = item->parent();
return getItemDir(parent) + QDir::separator() + QString("%1").arg(item->text());
}
/**
* @return Path of the DXF file that is represented by the given item.
*/
QString QG_LibraryWidget::getItemPath(QStandardItem* item) {
QItemSelectionModel* selDirView = dirView->selectionModel();
QModelIndex idx = selDirView->currentIndex();
QStandardItem * dirItem = dirModel->itemFromIndex ( idx );
QString dir = getItemDir(dirItem);
if (item) {
// List of all directories that contain part libraries:
QStringList directoryList = RS_SYSTEM->getDirectoryList("library");
QStringList::Iterator it;
QDir itemDir;
// look in all possible system directories for DXF files in the current library path:
for (it=directoryList.begin(); it!=directoryList.end(); ++it) {
itemDir.setPath((*it)+dir);
if (itemDir.exists()) {
QString f = (*it) + dir + QDir::separator() + item->text() + ".dxf";
if (QFileInfo(f).isReadable()) {
return f;
}
}
}
return "";
} else {
return "";
}
}
/**
* @return Pixmap that serves as icon for the given DXF File.
* The existing PNG file is returned or created and returned..
*
* @param dir Library directory (e.g. "/mechanical/screws")
* @param dxfFile File name (e.g. "screw1.dxf")
* @param dxfPath Full path to the existing DXF file on disk
* (e.g. /home/tux/.qcad/library/mechanical/screws/screw1.dxf)
*/
QIcon QG_LibraryWidget::getIcon(const QString& dir, const QString& dxfFile,
const QString& dxfPath) {
QString pngFile = getPathToPixmap(dir, dxfFile, dxfPath);
QFileInfo fiPng(pngFile);
// found existing thumbnail:
if (fiPng.isFile()) {
return QIcon(pngFile);
}
// default thumbnail:
else {
return QIcon(QPixmap(64,64));
}
}
/**
* @return Path to the thumbnail of the given DXF file. If no thumbnail exists, one is
* created in the user's home. If no thumbnail can be created, an empty string is returned.
*/
QString QG_LibraryWidget::getPathToPixmap(const QString& dir,
const QString& dxfFile,
const QString& dxfPath) {
// the thumbnail must be created in the user's home.
QString iconCacheLocation=QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QDir::separator() + "iconCache" + QDir::separator();
RS_DEBUG->print("QG_LibraryWidget::getPathToPixmap: "
"dir: '%s' dxfFile: '%s' dxfPath: '%s'",
dir.toLatin1().data(), dxfFile.toLatin1().data(), dxfPath.toLatin1().data());
// List of all directories that contain part libraries:
QStringList directoryList = RS_SYSTEM->getDirectoryList("library");
directoryList.prepend(iconCacheLocation);
QStringList::Iterator it;
QFileInfo fiDxf(dxfPath);
QString itemDir;
QString pngPath;
// look in all possible system directories for PNG files
// in the current library path:
for (it=directoryList.begin(); it!=directoryList.end(); ++it) {
itemDir = (*it)+dir;
pngPath = itemDir + QDir::separator() + fiDxf.baseName() + ".png";
RS_DEBUG->print("QG_LibraryWidget::getPathToPixmap: checking: '%s'",
pngPath.toLatin1().data());
QFileInfo fiPng(pngPath);
// the thumbnail exists:
if (fiPng.isFile()) {
RS_DEBUG->print("QG_LibraryWidget::getPathToPixmap: dxf date: %s, png date: %s",
fiDxf.lastModified().toString().toLatin1().data(), fiPng.lastModified().toString().toLatin1().data());
if (fiPng.lastModified() > fiDxf.lastModified()) {
RS_DEBUG->print("QG_LibraryWidget::getPathToPixmap: thumbnail found: '%s'",
pngPath.toLatin1().data());
return pngPath;
} else {
RS_DEBUG->print("QG_LibraryWidget::getPathToPixmap: thumbnail needs to be updated: '%s'",
pngPath.toLatin1().data());
}
}
}
// create all directories needed:
RS_SYSTEM->createPaths(iconCacheLocation + dir);
// QString foo=iconCacheLocation + dir + QDir::separator() + fiDxf.baseName() + ".png";
pngPath = iconCacheLocation + dir + QDir::separator() + fiDxf.baseName() + ".png";
QPixmap* buffer = new QPixmap(128,128);
RS_PainterQt painter(buffer);
painter.setBackground(RS_Color(255,255,255));
painter.eraseRect(0,0, 128,128);
RS_StaticGraphicView gv(128,128, &painter);
RS_Graphic graphic;
if (graphic.open(dxfPath, RS2::FormatUnknown)) {
gv.setContainer(&graphic);
gv.zoomAuto(false);
// gv.drawEntity(&graphic, true);
for (RS_Entity* e=graphic.firstEntity(RS2::ResolveAll);
e; e=graphic.nextEntity(RS2::ResolveAll)) {
if (e->rtti() != RS2::EntityHatch){
RS_Pen pen = e->getPen();
pen.setColor(Qt::black);
e->setPen(pen);
}
gv.drawEntity(&painter, e);
}
QImageWriter iio;
QImage img;
img = buffer->toImage();
img = img.scaled(64,64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
// iio.setImage(img);
iio.setFileName(pngPath);
iio.setFormat("PNG");
if (!iio.write(img)) {
pngPath = "";
RS_DEBUG->print(RS_Debug::D_ERROR,
"QG_LibraryWidget::getPathToPixmap: Cannot write thumbnail: '%s'",
pngPath.toLatin1().data());
}
} else {
RS_DEBUG->print(RS_Debug::D_ERROR,
"QG_LibraryWidget::getPathToPixmap: Cannot open file: '%s'",
dxfPath.toLatin1().data());
}
// GraphicView deletes painter
painter.end();
delete buffer;
return pngPath;
}