1 /*
2  * LibrePCB - Professional EDA for everyone!
3  * Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
4  * https://librepcb.org/
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 /*******************************************************************************
21  *  Includes
22  ******************************************************************************/
23 #include "dxfimportdialog.h"
24 
25 #include "../graphics/graphicslayer.h"
26 #include "../widgets/lengtheditbase.h"
27 #include "ui_dxfimportdialog.h"
28 
29 #include <librepcb/common/dialogs/filedialog.h>
30 
31 #include <QtCore>
32 
33 /*******************************************************************************
34  *  Namespace
35  ******************************************************************************/
36 namespace librepcb {
37 
38 /*******************************************************************************
39  *  Constructors / Destructor
40  ******************************************************************************/
41 
DxfImportDialog(QList<GraphicsLayer * > layers,const GraphicsLayerName & defaultLayer,bool supportHoles,const LengthUnit & lengthUnit,const QString & settingsPrefix,QWidget * parent)42 DxfImportDialog::DxfImportDialog(QList<GraphicsLayer*> layers,
43                                  const GraphicsLayerName& defaultLayer,
44                                  bool supportHoles,
45                                  const LengthUnit& lengthUnit,
46                                  const QString& settingsPrefix,
47                                  QWidget* parent) noexcept
48   : QDialog(parent),
49     mUi(new Ui::DxfImportDialog),
50     mSettingsPrefix(settingsPrefix),
51     mDefaultLayer(defaultLayer) {
52   mUi->setupUi(this);
53   mUi->cbxCirclesAsDrills->setVisible(supportHoles);
54   mUi->cbxLayer->setLayers(layers);
55   mUi->edtLineWidth->configure(lengthUnit, LengthEditBase::Steps::generic(),
56                                settingsPrefix % "/line_width");
57   mUi->edtPosX->configure(lengthUnit, LengthEditBase::Steps::generic(),
58                           settingsPrefix % "/pos_x");
59   mUi->edtPosY->configure(lengthUnit, LengthEditBase::Steps::generic(),
60                           settingsPrefix % "/pos_y");
61   connect(mUi->cbxInteractivePlacement, &QCheckBox::toggled, mUi->edtPosX,
62           &QCheckBox::setDisabled);
63   connect(mUi->cbxInteractivePlacement, &QCheckBox::toggled, mUi->edtPosY,
64           &QCheckBox::setDisabled);
65 
66   // Load initial values and window geometry.
67   try {
68     QSettings clientSettings;
69     mUi->cbxLayer->setCurrentLayer(GraphicsLayerName(
70         clientSettings.value(settingsPrefix % "/layer", *defaultLayer)
71             .toString()));
72     mUi->cbxCirclesAsDrills->setChecked(
73         clientSettings.value(settingsPrefix % "/circles_as_drills", false)
74             .toBool());
75     mUi->edtLineWidth->setValue(UnsignedLength(Length::fromMm(
76         clientSettings.value(settingsPrefix % "/line_width", "0").toString())));
77     mUi->spbxScaleFactor->setValue(
78         clientSettings.value(settingsPrefix % "/scale_factor", "1").toDouble());
79     mUi->cbxInteractivePlacement->setChecked(
80         clientSettings.value(settingsPrefix % "/interactive_placement", true)
81             .toBool());
82     mUi->edtPosX->setValue(Length::fromMm(
83         clientSettings.value(settingsPrefix % "/pos_x", "0").toString()));
84     mUi->edtPosY->setValue(Length::fromMm(
85         clientSettings.value(settingsPrefix % "/pos_y", "0").toString()));
86     restoreGeometry(clientSettings.value(settingsPrefix % "/window_geometry")
87                         .toByteArray());
88   } catch (const Exception& e) {
89     qCritical() << "Error while initializing DXF import dialog:" << e.getMsg();
90   }
91 }
92 
~DxfImportDialog()93 DxfImportDialog::~DxfImportDialog() noexcept {
94   // Save the values and window geometry.
95   QSettings clientSettings;
96   if (auto layerName = mUi->cbxLayer->getCurrentLayerName()) {
97     clientSettings.setValue(mSettingsPrefix % "/layer", **layerName);
98   }
99   clientSettings.setValue(mSettingsPrefix % "/circles_as_drills",
100                           mUi->cbxCirclesAsDrills->isChecked());
101   clientSettings.setValue(mSettingsPrefix % "/line_width",
102                           mUi->edtLineWidth->getValue()->toMmString());
103   clientSettings.setValue(mSettingsPrefix % "/scale_factor",
104                           mUi->spbxScaleFactor->value());
105   clientSettings.setValue(mSettingsPrefix % "/interactive_placement",
106                           mUi->cbxInteractivePlacement->isChecked());
107   clientSettings.setValue(mSettingsPrefix % "/pos_x",
108                           mUi->edtPosX->getValue().toMmString());
109   clientSettings.setValue(mSettingsPrefix % "/pos_y",
110                           mUi->edtPosY->getValue().toMmString());
111   clientSettings.setValue(mSettingsPrefix % "/window_geometry", saveGeometry());
112 }
113 
114 /*******************************************************************************
115  *  Getters
116  ******************************************************************************/
117 
getLayerName() const118 GraphicsLayerName DxfImportDialog::getLayerName() const noexcept {
119   if (auto layer = mUi->cbxLayer->getCurrentLayerName()) {
120     return *layer;
121   } else {
122     return mDefaultLayer;
123   }
124 }
125 
getImportCirclesAsDrills() const126 bool DxfImportDialog::getImportCirclesAsDrills() const noexcept {
127   return mUi->cbxCirclesAsDrills->isChecked();
128 }
129 
getLineWidth() const130 UnsignedLength DxfImportDialog::getLineWidth() const noexcept {
131   return mUi->edtLineWidth->getValue();
132 }
133 
getScaleFactor() const134 qreal DxfImportDialog::getScaleFactor() const noexcept {
135   return mUi->spbxScaleFactor->value();
136 }
137 
getPlacementPosition() const138 tl::optional<Point> DxfImportDialog::getPlacementPosition() const noexcept {
139   if (mUi->cbxInteractivePlacement->isChecked()) {
140     return tl::nullopt;
141   } else {
142     return Point(mUi->edtPosX->getValue(), mUi->edtPosY->getValue());
143   }
144 }
145 
146 /*******************************************************************************
147  *  General Methods
148  ******************************************************************************/
149 
chooseFile() const150 FilePath DxfImportDialog::chooseFile() const noexcept {
151   QSettings clientSettings;
152   QString key = mSettingsPrefix % "/file";
153   QString selectedFile = clientSettings.value(key, QDir::homePath()).toString();
154   FilePath fp(FileDialog::getOpenFileName(parentWidget(), tr("Choose file"),
155                                           selectedFile, "*.dxf;;*"));
156   if (fp.isValid()) {
157     clientSettings.setValue(key, fp.toStr());
158   }
159   return fp;
160 }
161 
throwNoObjectsImportedError()162 void DxfImportDialog::throwNoObjectsImportedError() {
163   throw RuntimeError(
164       __FILE__, __LINE__,
165       tr("The selected file does not contain any objects to import."));
166 }
167 
168 /*******************************************************************************
169  *  End of File
170  ******************************************************************************/
171 
172 }  // namespace librepcb
173