mirror of https://github.com/KLayout/klayout.git
1709 lines
63 KiB
C++
1709 lines
63 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2018 Matthias Koefferlein
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
#include "ui_GerberImportDialog.h"
|
|
#include "dbGerberImporter.h"
|
|
|
|
#include "layFileDialog.h"
|
|
#include "layDialogs.h"
|
|
#include "layConverters.h"
|
|
#include "layGerberImportDialog.h"
|
|
|
|
#include "tlExceptions.h"
|
|
#include "tlXMLParser.h"
|
|
|
|
#include <QFileDialog>
|
|
#include <QItemDelegate>
|
|
#include <QHeaderView>
|
|
#include <QMessageBox>
|
|
|
|
#include <fstream>
|
|
|
|
namespace lay
|
|
{
|
|
|
|
// -----------------------------------------------------------------------------------------
|
|
// GerberImportDialogFileColumnEditorWidget implementation
|
|
|
|
GerberImportDialogFileColumnEditorWidget::GerberImportDialogFileColumnEditorWidget (QWidget *parent, db::GerberImportData *data)
|
|
: QFrame (parent), mp_data (data)
|
|
{
|
|
QHBoxLayout *layout = new QHBoxLayout (this);
|
|
layout->setSpacing (0);
|
|
layout->setMargin (0);
|
|
setLayout (layout);
|
|
setFocusPolicy (Qt::ClickFocus);
|
|
|
|
mp_filename_edit = new QLineEdit (this);
|
|
layout->addWidget (mp_filename_edit);
|
|
mp_filename_edit->setFocusPolicy (Qt::ClickFocus);
|
|
QSizePolicy sp = mp_filename_edit->sizePolicy ();
|
|
sp.setVerticalPolicy (QSizePolicy::Expanding);
|
|
mp_filename_edit->setSizePolicy (sp);
|
|
|
|
mp_browse_button = new QToolButton (this);
|
|
mp_browse_button->setText (QString::fromUtf8 ("..."));
|
|
mp_browse_button->setFocusPolicy (Qt::NoFocus);
|
|
layout->addWidget (mp_browse_button);
|
|
connect (mp_browse_button, SIGNAL (clicked ()), this, SLOT (browse_clicked ()));
|
|
|
|
setFocusProxy (mp_filename_edit);
|
|
}
|
|
|
|
void
|
|
GerberImportDialogFileColumnEditorWidget::set_filename (const std::string &s)
|
|
{
|
|
QDir base_dir (tl::to_qstring (mp_data->base_dir));
|
|
QString text (base_dir.relativeFilePath (tl::to_qstring (s)));
|
|
if (mp_filename_edit->text () != text) {
|
|
mp_filename_edit->setText (base_dir.relativeFilePath (tl::to_qstring (s)));
|
|
}
|
|
}
|
|
|
|
std::string
|
|
GerberImportDialogFileColumnEditorWidget::get_filename () const
|
|
{
|
|
return tl::to_string (mp_filename_edit->text ());
|
|
}
|
|
|
|
void
|
|
GerberImportDialogFileColumnEditorWidget::browse_clicked ()
|
|
{
|
|
QFileInfo file (tl::to_qstring (get_filename ()));
|
|
if (get_filename ().empty ()) {
|
|
file = QFileInfo (tl::to_qstring (mp_data->base_dir));
|
|
} else if (! QFileInfo (tl::to_qstring (get_filename ())).isAbsolute ()) {
|
|
file = QFileInfo (QDir (tl::to_qstring (mp_data->base_dir)), tl::to_qstring (get_filename ()));
|
|
}
|
|
|
|
std::string new_file (tl::to_string (file.absoluteFilePath ()));
|
|
lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("PCB data file")), tl::to_string (QObject::tr ("All files (*)")));
|
|
if (open_dialog.get_open (new_file)) {
|
|
set_filename (new_file);
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------------
|
|
// GerberImportDialogMetalLayerColumnEditorWidget implementation
|
|
|
|
GerberImportDialogMetalLayerColumnEditorWidget::GerberImportDialogMetalLayerColumnEditorWidget (QWidget *parent, db::GerberImportData *data)
|
|
: QComboBox (parent)
|
|
{
|
|
for (int i = 0; i < int (data->artwork_files.size ()); ++i) {
|
|
addItem (tl::to_qstring (tl::sprintf (tl::to_string (QObject::tr ("Metal %d")), i + 1)));
|
|
}
|
|
}
|
|
|
|
void
|
|
GerberImportDialogMetalLayerColumnEditorWidget::set_layer (int layer)
|
|
{
|
|
setCurrentIndex (layer);
|
|
}
|
|
|
|
int
|
|
GerberImportDialogMetalLayerColumnEditorWidget::get_layer () const
|
|
{
|
|
return currentIndex ();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------------
|
|
// GerberImportDialogNoEditDelegate
|
|
|
|
class GerberImportDialogNoEditDelegate
|
|
: public QItemDelegate
|
|
{
|
|
public:
|
|
GerberImportDialogNoEditDelegate (QWidget *parent)
|
|
: QItemDelegate (parent)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
QWidget *createEditor (QWidget * /*parent*/, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const
|
|
{
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------------------
|
|
// GerberImportDialogMetalLayerColumnDelegate definition and implementation
|
|
|
|
class GerberImportDialogMetalLayerColumnDelegate
|
|
: public QItemDelegate
|
|
{
|
|
public:
|
|
GerberImportDialogMetalLayerColumnDelegate (QWidget *parent, db::GerberImportData *data)
|
|
: QItemDelegate (parent), mp_data (data)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const
|
|
{
|
|
return new GerberImportDialogMetalLayerColumnEditorWidget (parent, mp_data);
|
|
}
|
|
|
|
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex & /*index*/) const
|
|
{
|
|
editor->setGeometry(option.rect);
|
|
}
|
|
|
|
void setEditorData (QWidget *widget, const QModelIndex &index) const
|
|
{
|
|
GerberImportDialogMetalLayerColumnEditorWidget *editor = dynamic_cast<GerberImportDialogMetalLayerColumnEditorWidget *> (widget);
|
|
if (editor) {
|
|
editor->set_layer (index.model ()->data (index, Qt::UserRole).toInt ());
|
|
}
|
|
}
|
|
|
|
void setModelData (QWidget *widget, QAbstractItemModel *model, const QModelIndex &index) const
|
|
{
|
|
GerberImportDialogMetalLayerColumnEditorWidget *editor = dynamic_cast<GerberImportDialogMetalLayerColumnEditorWidget *> (widget);
|
|
if (editor) {
|
|
int l = editor->get_layer ();
|
|
model->setData (index, QVariant (l), Qt::UserRole);
|
|
if (l < 0) {
|
|
model->setData (index, QVariant (QString::fromUtf8 ("...")), Qt::DisplayRole);
|
|
model->setData (index, widget->palette ().color (QPalette::Disabled, QPalette::Text), Qt::ForegroundRole);
|
|
} else {
|
|
model->setData (index, tl::to_qstring (tl::sprintf (tl::to_string (QObject::tr ("Metal %d")), l + 1)), Qt::DisplayRole);
|
|
model->setData (index, widget->palette ().color (QPalette::Active, QPalette::Text), Qt::ForegroundRole);
|
|
}
|
|
}
|
|
}
|
|
|
|
QSize sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const
|
|
{
|
|
QWidget *editor = createEditor (0, option, index);
|
|
QSize size = editor->sizeHint ();
|
|
delete editor;
|
|
return size;
|
|
}
|
|
|
|
private:
|
|
db::GerberImportData *mp_data;
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------------------
|
|
// GerberImportDialogFileColumnDelegate definition and implementation
|
|
|
|
class GerberImportDialogFileColumnDelegate
|
|
: public QItemDelegate
|
|
{
|
|
public:
|
|
GerberImportDialogFileColumnDelegate (QWidget *parent, db::GerberImportData *data)
|
|
: QItemDelegate (parent), mp_data (data)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const
|
|
{
|
|
return new GerberImportDialogFileColumnEditorWidget (parent, mp_data);
|
|
}
|
|
|
|
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex & /*index*/) const
|
|
{
|
|
editor->setGeometry(option.rect);
|
|
}
|
|
|
|
void setEditorData (QWidget *widget, const QModelIndex &index) const
|
|
{
|
|
GerberImportDialogFileColumnEditorWidget *editor = dynamic_cast<GerberImportDialogFileColumnEditorWidget *> (widget);
|
|
if (editor) {
|
|
std::string fn (tl::to_string (index.model ()->data (index, Qt::UserRole).toString ()));
|
|
editor->set_filename (fn);
|
|
}
|
|
}
|
|
|
|
void setModelData (QWidget *widget, QAbstractItemModel *model, const QModelIndex &index) const
|
|
{
|
|
GerberImportDialogFileColumnEditorWidget *editor = dynamic_cast<GerberImportDialogFileColumnEditorWidget *> (widget);
|
|
if (editor) {
|
|
|
|
model->setData (index, QVariant (tl::to_qstring (editor->get_filename ())), Qt::UserRole);
|
|
if (! editor->get_filename ().empty ()) {
|
|
|
|
model->setData (index, QVariant (tl::to_qstring (editor->get_filename ())), Qt::DisplayRole);
|
|
|
|
QFileInfo file_info (tl::to_qstring (editor->get_filename ()));
|
|
if (! mp_data->base_dir.empty () && ! file_info.isAbsolute ()) {
|
|
file_info = QFileInfo (QDir (tl::to_qstring (mp_data->base_dir)), tl::to_qstring (editor->get_filename ()));
|
|
}
|
|
|
|
if (file_info.exists () && file_info.isReadable ()) {
|
|
model->setData (index, widget->palette ().color (QPalette::Active, QPalette::Text), Qt::ForegroundRole);
|
|
model->setData (index, widget->palette ().color (QPalette::Active, QPalette::Base), Qt::BackgroundRole);
|
|
} else {
|
|
model->setData (index, QColor (Qt::red), Qt::ForegroundRole);
|
|
model->setData (index, QColor (Qt::red).lighter (180), Qt::BackgroundRole);
|
|
}
|
|
|
|
} else {
|
|
|
|
model->setData (index, QVariant (QObject::tr ("Click here to enter file name")), Qt::DisplayRole);
|
|
model->setData (index, widget->palette ().color (QPalette::Disabled, QPalette::Text), Qt::ForegroundRole);
|
|
model->setData (index, widget->palette ().color (QPalette::Disabled, QPalette::Base), Qt::BackgroundRole);
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
QSize sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const
|
|
{
|
|
QWidget *editor = createEditor (0, option, index);
|
|
QSize size = editor->sizeHint ();
|
|
delete editor;
|
|
return size;
|
|
}
|
|
|
|
private:
|
|
db::GerberImportData *mp_data;
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------------------
|
|
// GerberImportDialog implementation
|
|
|
|
GerberImportDialog::GerberImportDialog (QWidget *parent, db::GerberImportData *data)
|
|
: QDialog (parent), mp_data (data)
|
|
{
|
|
mp_ui = new Ui::GerberImportDialog ();
|
|
mp_ui->setupUi (this);
|
|
|
|
connect (mp_ui->last_pb, SIGNAL (clicked ()), this, SLOT (last_page ()));
|
|
connect (mp_ui->next_pb, SIGNAL (clicked ()), this, SLOT (next_page ()));
|
|
connect (mp_ui->layer_properties_file_browse_pb, SIGNAL (clicked ()), this, SLOT (browse_layer_properties_file ()));
|
|
connect (mp_ui->base_dir_pb, SIGNAL (clicked ()), this, SLOT (browse_base_dir ()));
|
|
|
|
connect (mp_ui->add_target_layer_pb, SIGNAL (clicked ()), this, SLOT (add_target_layer ()));
|
|
connect (mp_ui->delete_target_layer_pb, SIGNAL (clicked ()), this, SLOT (delete_target_layer ()));
|
|
connect (mp_ui->move_target_layer_up_pb, SIGNAL (clicked ()), this, SLOT (move_target_layer_up ()));
|
|
connect (mp_ui->move_target_layer_down_pb, SIGNAL (clicked ()), this, SLOT (move_target_layer_down ()));
|
|
|
|
connect (mp_ui->free_add_target_layer_pb, SIGNAL (clicked ()), this, SLOT (add_target_layer ()));
|
|
connect (mp_ui->free_delete_target_layer_pb, SIGNAL (clicked ()), this, SLOT (delete_target_layer ()));
|
|
connect (mp_ui->free_move_target_layer_up_pb, SIGNAL (clicked ()), this, SLOT (move_target_layer_up ()));
|
|
connect (mp_ui->free_move_target_layer_down_pb, SIGNAL (clicked ()), this, SLOT (move_target_layer_down ()));
|
|
|
|
connect (mp_ui->reset_mapping_pb, SIGNAL (clicked ()), this, SLOT (reset_free_mapping ()));
|
|
|
|
connect (mp_ui->layout_layers_tree, SIGNAL (itemDoubleClicked (QTreeWidgetItem *, int)), this, SLOT (layout_layer_double_clicked (QTreeWidgetItem *, int)));
|
|
connect (mp_ui->free_layout_layers_tree, SIGNAL (itemDoubleClicked (QTreeWidgetItem *, int)), this, SLOT (layout_layer_double_clicked (QTreeWidgetItem *, int)));
|
|
|
|
connect (mp_ui->add_free_file_pb, SIGNAL (clicked ()), this, SLOT (add_free_file ()));
|
|
connect (mp_ui->delete_free_file_pb, SIGNAL (clicked ()), this, SLOT (delete_free_file ()));
|
|
connect (mp_ui->move_free_file_up_pb, SIGNAL (clicked ()), this, SLOT (move_free_file_up ()));
|
|
connect (mp_ui->move_free_file_down_pb, SIGNAL (clicked ()), this, SLOT (move_free_file_down ()));
|
|
|
|
mp_ui->artwork_files_tree->setItemDelegateForColumn (0, new GerberImportDialogNoEditDelegate (mp_ui->artwork_files_tree));
|
|
mp_ui->artwork_files_tree->setItemDelegateForColumn (1, new GerberImportDialogFileColumnDelegate (mp_ui->artwork_files_tree, mp_data));
|
|
|
|
mp_ui->free_layer_mapping_tree->setItemDelegateForColumn (0, new GerberImportDialogNoEditDelegate (mp_ui->free_layer_mapping_tree));
|
|
mp_ui->free_files_tree->setItemDelegateForColumn (0, new GerberImportDialogFileColumnDelegate (mp_ui->free_files_tree, mp_data));
|
|
connect (mp_ui->free_layer_mapping_tree, SIGNAL (itemClicked (QTreeWidgetItem *, int)), this, SLOT (free_layer_mapping_item_clicked (QTreeWidgetItem *, int)));
|
|
|
|
mp_ui->drill_files_tree->setItemDelegateForColumn (0, new GerberImportDialogNoEditDelegate (mp_ui->artwork_files_tree));
|
|
mp_ui->drill_files_tree->setItemDelegateForColumn (1, new GerberImportDialogMetalLayerColumnDelegate (mp_ui->artwork_files_tree, mp_data));
|
|
mp_ui->drill_files_tree->setItemDelegateForColumn (2, new GerberImportDialogMetalLayerColumnDelegate (mp_ui->artwork_files_tree, mp_data));
|
|
mp_ui->drill_files_tree->setItemDelegateForColumn (3, new GerberImportDialogFileColumnDelegate (mp_ui->artwork_files_tree, mp_data));
|
|
|
|
m_open_action = new QAction (QObject::tr ("Open Project"), mp_ui->file_menu);
|
|
m_saveas_action = new QAction (QObject::tr ("Save Project"), mp_ui->file_menu);
|
|
m_reset_action = new QAction (QObject::tr ("New Project"), mp_ui->file_menu);
|
|
|
|
mp_ui->file_menu->addAction (m_open_action);
|
|
mp_ui->file_menu->addAction (m_saveas_action);
|
|
mp_ui->file_menu->addAction (m_reset_action);
|
|
|
|
connect (m_open_action, SIGNAL (triggered ()), this, SLOT (open_clicked ()));
|
|
connect (m_saveas_action, SIGNAL (triggered ()), this, SLOT (saveas_clicked ()));
|
|
connect (m_reset_action, SIGNAL (triggered ()), this, SLOT (reset_clicked ()));
|
|
}
|
|
|
|
GerberImportDialog::~GerberImportDialog ()
|
|
{
|
|
delete mp_ui;
|
|
mp_ui = 0;
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::reset_clicked ()
|
|
{
|
|
// Commit everything that is not loaded
|
|
try {
|
|
commit_page ();
|
|
} catch (...) {
|
|
// ..
|
|
}
|
|
|
|
mp_data->reset ();
|
|
mp_ui->central_stack->setCurrentIndex (0);
|
|
update ();
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::saveas_clicked ()
|
|
{
|
|
BEGIN_PROTECTED
|
|
|
|
commit_page ();
|
|
|
|
// Get the name of the file to save
|
|
lay::FileDialog save_dialog (this, tl::to_string (QObject::tr ("Gerber Import Project File")), tl::to_string (QObject::tr ("PCB project file (*.pcb);;All files (*)")));
|
|
std::string fn = mp_data->current_file;
|
|
if (save_dialog.get_save (fn)) {
|
|
mp_data->save (fn);
|
|
}
|
|
|
|
END_PROTECTED
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::open_clicked ()
|
|
{
|
|
// Commit everything that is not loaded
|
|
try {
|
|
commit_page ();
|
|
} catch (...) {
|
|
// ..
|
|
}
|
|
|
|
BEGIN_PROTECTED
|
|
|
|
// Get the name of the file to open
|
|
lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("Gerber Import Project File")), tl::to_string (QObject::tr ("PCB project file (*.pcb);;All files (*)")));
|
|
std::string fn = mp_data->current_file;
|
|
if (open_dialog.get_open (fn)) {
|
|
|
|
// set the base dir to point to where the project file is located
|
|
QFileInfo fi (tl::to_qstring (fn));
|
|
mp_data->base_dir = tl::to_string (fi.absoluteDir ().path ());
|
|
mp_data->load (fn);
|
|
|
|
}
|
|
|
|
END_PROTECTED
|
|
|
|
update ();
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::browse_layer_properties_file ()
|
|
{
|
|
std::string file = tl::to_string (mp_ui->layer_properties_file_le->text ());
|
|
lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("Layer Properties File")), tl::to_string (QObject::tr ("Layer properties files (*.lyp);;All files (*)")));
|
|
if (open_dialog.get_open (file)) {
|
|
QDir base_dir (tl::to_qstring (mp_data->base_dir));
|
|
mp_ui->layer_properties_file_le->setText (base_dir.relativeFilePath (tl::to_qstring (file)));
|
|
}
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::browse_base_dir ()
|
|
{
|
|
QString base_dir = mp_ui->base_dir_le->text ();
|
|
base_dir = QFileDialog::getExistingDirectory (this, QObject::tr ("Get Base Directory"), base_dir);
|
|
if (! base_dir.isNull ()) {
|
|
mp_ui->base_dir_le->setText (base_dir);
|
|
}
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::reject ()
|
|
{
|
|
try {
|
|
commit_page ();
|
|
} catch (...) {
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
QDialog::reject ();
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::accept ()
|
|
{
|
|
BEGIN_PROTECTED
|
|
|
|
commit_page ();
|
|
QDialog::accept ();
|
|
|
|
END_PROTECTED
|
|
}
|
|
|
|
int
|
|
GerberImportDialog::exec ()
|
|
{
|
|
mp_ui->central_stack->setCurrentIndex (0);
|
|
update ();
|
|
|
|
return QDialog::exec ();
|
|
}
|
|
|
|
/*
|
|
* 0 - General
|
|
* 1 - Layers (stacked)
|
|
* 2 - Stack (stacked)
|
|
* 3 - Artwork files (stacked)
|
|
* 4 - Drill files (stacked)
|
|
* 5 - Layers (free)
|
|
* 6 - Mapping (free)
|
|
* 7 - Reference points
|
|
* 8 - Options
|
|
*/
|
|
static int next_pages_stacked[] = { 1, 2, 3, 4, 8, 8, 8, 8, 9, -1 };
|
|
static int next_pages_free[] = { 5, 5, 5, 5, 5, 6, 7, 8, 9, -1 };
|
|
static int prev_pages_stacked[] = { -1, 0, 1, 2, 3, 4, 4, 4, 4, 8 };
|
|
static int prev_pages_free[] = { -1, 0, 0, 0, 0, 0, 5, 6, 7, 8 };
|
|
|
|
void
|
|
GerberImportDialog::next_page ()
|
|
{
|
|
BEGIN_PROTECTED
|
|
commit_page ();
|
|
|
|
int index = mp_ui->central_stack->currentIndex ();
|
|
if (index >= 0 && index < int (sizeof (next_pages_stacked) / sizeof (next_pages_stacked[0]))) {
|
|
index = mp_data->free_layer_mapping ? next_pages_free [index] : next_pages_stacked [index];
|
|
if (index >= 0) {
|
|
mp_ui->central_stack->setCurrentIndex (index);
|
|
enter_page ();
|
|
}
|
|
}
|
|
|
|
update ();
|
|
END_PROTECTED
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::last_page ()
|
|
{
|
|
// "safe" commit
|
|
try {
|
|
commit_page ();
|
|
} catch (...) { }
|
|
|
|
BEGIN_PROTECTED
|
|
|
|
int index = mp_ui->central_stack->currentIndex ();
|
|
if (index >= 0 && index < int (sizeof (next_pages_stacked) / sizeof (next_pages_stacked[0]))) {
|
|
index = mp_data->free_layer_mapping ? prev_pages_free [index] : prev_pages_stacked [index];
|
|
if (index >= 0) {
|
|
mp_ui->central_stack->setCurrentIndex (index);
|
|
}
|
|
}
|
|
|
|
update ();
|
|
END_PROTECTED
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::add_target_layer ()
|
|
{
|
|
QTreeWidget *tree = mp_data->free_layer_mapping ? mp_ui->free_layout_layers_tree : mp_ui->layout_layers_tree;
|
|
|
|
lay::NewLayerPropertiesDialog lp_dialog (this);
|
|
|
|
db::LayerProperties props;
|
|
|
|
// prefill with the current item's data ...
|
|
if (tree->currentItem ()) {
|
|
int n = tree->currentItem ()->data (0, Qt::UserRole).toInt ();
|
|
if (n >= 0 && n < int (mp_data->layout_layers.size ())) {
|
|
props = mp_data->layout_layers [n];
|
|
}
|
|
}
|
|
|
|
if (lp_dialog.exec_dialog (props)) {
|
|
mp_data->layout_layers.push_back (props);
|
|
update ();
|
|
tree->setCurrentItem (tree->topLevelItem (int (mp_data->layout_layers.size () - 1)));
|
|
}
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::delete_target_layer ()
|
|
{
|
|
QTreeWidget *tree = mp_data->free_layer_mapping ? mp_ui->free_layout_layers_tree : mp_ui->layout_layers_tree;
|
|
|
|
QList<QTreeWidgetItem *> selected = tree->selectedItems ();
|
|
|
|
std::set <int> selected_indices;
|
|
for (QList<QTreeWidgetItem *>::const_iterator s = selected.begin (); s != selected.end (); ++s) {
|
|
int n = (*s)->data (0, Qt::UserRole).toInt ();
|
|
if (n >= 0 && n < int (mp_data->layout_layers.size ())) {
|
|
selected_indices.insert (n);
|
|
}
|
|
}
|
|
|
|
std::vector <db::LayerProperties>::iterator lw = mp_data->layout_layers.begin ();
|
|
for (std::vector <db::LayerProperties>::iterator l = mp_data->layout_layers.begin (); l != mp_data->layout_layers.end (); ++l) {
|
|
if (selected_indices.find (int (std::distance (mp_data->layout_layers.begin (), l))) == selected_indices.end ()) {
|
|
*lw++ = *l;
|
|
}
|
|
}
|
|
mp_data->layout_layers.erase (lw, mp_data->layout_layers.end ());
|
|
|
|
update ();
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::move_target_layer_up ()
|
|
{
|
|
QTreeWidget *tree = mp_data->free_layer_mapping ? mp_ui->free_layout_layers_tree : mp_ui->layout_layers_tree;
|
|
|
|
QList<QTreeWidgetItem *> selected = tree->selectedItems ();
|
|
|
|
std::set <int> selected_indices;
|
|
for (QList<QTreeWidgetItem *>::const_iterator s = selected.begin (); s != selected.end (); ++s) {
|
|
int n = (*s)->data (0, Qt::UserRole).toInt ();
|
|
if (n >= 0 && n < int (mp_data->layout_layers.size ())) {
|
|
selected_indices.insert (n);
|
|
}
|
|
}
|
|
|
|
QTreeWidgetItem *current = tree->currentItem ();
|
|
int n_current = current ? current->data (0, Qt::UserRole).toInt () : -1;
|
|
|
|
for (std::vector <db::LayerProperties>::iterator l = mp_data->layout_layers.begin (); l != mp_data->layout_layers.end (); ++l) {
|
|
int n = int (std::distance (mp_data->layout_layers.begin (), l));
|
|
if (selected_indices.find (n + 1) != selected_indices.end () && selected_indices.find (n) == selected_indices.end ()) {
|
|
std::swap (mp_data->layout_layers [n + 1], mp_data->layout_layers [n]);
|
|
selected_indices.erase (n + 1);
|
|
selected_indices.insert (n);
|
|
if (n_current == n + 1) {
|
|
n_current = n;
|
|
}
|
|
}
|
|
}
|
|
|
|
update ();
|
|
|
|
// select the new items
|
|
for (std::set <int>::const_iterator s = selected_indices.begin (); s != selected_indices.end (); ++s) {
|
|
tree->selectionModel ()->select (tree->model ()->index (*s, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
|
|
}
|
|
|
|
if (n_current >= 0) {
|
|
tree->selectionModel ()->select (tree->model ()->index (n_current, 0), QItemSelectionModel::Current | QItemSelectionModel::Rows);
|
|
}
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::move_target_layer_down ()
|
|
{
|
|
QTreeWidget *tree = mp_data->free_layer_mapping ? mp_ui->free_layout_layers_tree : mp_ui->layout_layers_tree;
|
|
|
|
QList<QTreeWidgetItem *> selected = tree->selectedItems ();
|
|
|
|
std::set <int> selected_indices;
|
|
for (QList<QTreeWidgetItem *>::const_iterator s = selected.begin (); s != selected.end (); ++s) {
|
|
int n = (*s)->data (0, Qt::UserRole).toInt ();
|
|
if (n >= 0 && n < int (mp_data->layout_layers.size ())) {
|
|
selected_indices.insert (n);
|
|
}
|
|
}
|
|
|
|
QTreeWidgetItem *current = tree->currentItem ();
|
|
int n_current = current ? current->data (0, Qt::UserRole).toInt () : -1;
|
|
|
|
for (std::vector <db::LayerProperties>::iterator l = mp_data->layout_layers.end (); l != mp_data->layout_layers.begin (); ) {
|
|
--l;
|
|
int n = int (std::distance (mp_data->layout_layers.begin (), l));
|
|
if (selected_indices.find (n - 1) != selected_indices.end () && selected_indices.find (n) == selected_indices.end ()) {
|
|
std::swap (mp_data->layout_layers [n - 1], mp_data->layout_layers [n]);
|
|
selected_indices.erase (n - 1);
|
|
selected_indices.insert (n);
|
|
if (n_current == n - 1) {
|
|
n_current = n;
|
|
}
|
|
}
|
|
}
|
|
|
|
update ();
|
|
|
|
// select the new items
|
|
for (std::set <int>::const_iterator s = selected_indices.begin (); s != selected_indices.end (); ++s) {
|
|
tree->selectionModel ()->select (tree->model ()->index (*s, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
|
|
}
|
|
|
|
if (n_current >= 0) {
|
|
tree->selectionModel ()->select (mp_ui->layout_layers_tree->model ()->index (n_current, 0), QItemSelectionModel::Current | QItemSelectionModel::Rows);
|
|
}
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::add_free_file ()
|
|
{
|
|
// "safe" commit
|
|
try {
|
|
commit_page ();
|
|
} catch (...) { }
|
|
|
|
QTreeWidget *tree = mp_ui->free_files_tree;
|
|
|
|
std::vector <std::string> new_files;
|
|
|
|
lay::FileDialog open_dialog (this, tl::to_string (QObject::tr ("PCB data file")), tl::to_string (QObject::tr ("All files (*)")));
|
|
if (open_dialog.get_open (new_files, mp_data->base_dir)) {
|
|
|
|
std::sort (new_files.begin (), new_files.end ());
|
|
|
|
QDir base_dir (tl::to_qstring (mp_data->base_dir));
|
|
|
|
for (std::vector <std::string>::const_iterator f = new_files.begin (); f != new_files.end (); ++f) {
|
|
mp_data->free_files.push_back (db::GerberFreeFileDescriptor ());
|
|
mp_data->free_files.back ().filename = tl::to_string (base_dir.relativeFilePath (tl::to_qstring (*f)));
|
|
}
|
|
|
|
update ();
|
|
tree->setCurrentItem (tree->topLevelItem (int (mp_data->free_files.size () - 1)));
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::delete_free_file ()
|
|
{
|
|
QTreeWidget *tree = mp_ui->free_files_tree;
|
|
|
|
QList<QTreeWidgetItem *> selected = tree->selectedItems ();
|
|
|
|
std::set <int> selected_indices;
|
|
for (QList<QTreeWidgetItem *>::const_iterator s = selected.begin (); s != selected.end (); ++s) {
|
|
int n = (*s)->data (0, Qt::UserRole + 1).toInt ();
|
|
if (n >= 0 && n < int (mp_data->free_files.size ())) {
|
|
selected_indices.insert (n);
|
|
}
|
|
}
|
|
|
|
// "safe" commit
|
|
try {
|
|
commit_page ();
|
|
} catch (...) { }
|
|
|
|
std::vector <db::GerberFreeFileDescriptor>::iterator lw = mp_data->free_files.begin ();
|
|
for (std::vector <db::GerberFreeFileDescriptor>::iterator l = mp_data->free_files.begin (); l != mp_data->free_files.end (); ++l) {
|
|
if (selected_indices.find (int (std::distance (mp_data->free_files.begin (), l))) == selected_indices.end ()) {
|
|
*lw++ = *l;
|
|
}
|
|
}
|
|
mp_data->free_files.erase (lw, mp_data->free_files.end ());
|
|
|
|
update ();
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::move_free_file_up ()
|
|
{
|
|
QTreeWidget *tree = mp_ui->free_files_tree;
|
|
|
|
QList<QTreeWidgetItem *> selected = tree->selectedItems ();
|
|
|
|
std::set <int> selected_indices;
|
|
for (QList<QTreeWidgetItem *>::const_iterator s = selected.begin (); s != selected.end (); ++s) {
|
|
int n = (*s)->data (0, Qt::UserRole + 1).toInt ();
|
|
if (n >= 0 && n < int (mp_data->free_files.size ())) {
|
|
selected_indices.insert (n);
|
|
}
|
|
}
|
|
|
|
QTreeWidgetItem *current = tree->currentItem ();
|
|
int n_current = current ? current->data (0, Qt::UserRole + 1).toInt () : -1;
|
|
|
|
// "safe" commit
|
|
try {
|
|
commit_page ();
|
|
} catch (...) { }
|
|
|
|
for (std::vector <db::GerberFreeFileDescriptor>::iterator l = mp_data->free_files.begin (); l != mp_data->free_files.end (); ++l) {
|
|
int n = int (std::distance (mp_data->free_files.begin (), l));
|
|
if (selected_indices.find (n + 1) != selected_indices.end () && selected_indices.find (n) == selected_indices.end ()) {
|
|
std::swap (mp_data->free_files [n + 1], mp_data->free_files [n]);
|
|
selected_indices.erase (n + 1);
|
|
selected_indices.insert (n);
|
|
if (n_current == n + 1) {
|
|
n_current = n;
|
|
}
|
|
}
|
|
}
|
|
|
|
update ();
|
|
|
|
// select the new items
|
|
for (std::set <int>::const_iterator s = selected_indices.begin (); s != selected_indices.end (); ++s) {
|
|
tree->selectionModel ()->select (tree->model ()->index (*s, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
|
|
}
|
|
|
|
if (n_current >= 0) {
|
|
tree->selectionModel ()->select (mp_ui->layout_layers_tree->model ()->index (n_current, 0), QItemSelectionModel::Current | QItemSelectionModel::Rows);
|
|
}
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::move_free_file_down ()
|
|
{
|
|
QTreeWidget *tree = mp_ui->free_files_tree;
|
|
|
|
QList<QTreeWidgetItem *> selected = tree->selectedItems ();
|
|
|
|
std::set <int> selected_indices;
|
|
for (QList<QTreeWidgetItem *>::const_iterator s = selected.begin (); s != selected.end (); ++s) {
|
|
int n = (*s)->data (0, Qt::UserRole + 1).toInt ();
|
|
if (n >= 0 && n < int (mp_data->free_files.size ())) {
|
|
selected_indices.insert (n);
|
|
}
|
|
}
|
|
|
|
QTreeWidgetItem *current = tree->currentItem ();
|
|
int n_current = current ? current->data (0, Qt::UserRole + 1).toInt () : -1;
|
|
|
|
// "safe" commit
|
|
try {
|
|
commit_page ();
|
|
} catch (...) { }
|
|
|
|
for (std::vector <db::GerberFreeFileDescriptor>::iterator l = mp_data->free_files.end (); l != mp_data->free_files.begin (); ) {
|
|
--l;
|
|
int n = int (std::distance (mp_data->free_files.begin (), l));
|
|
if (selected_indices.find (n - 1) != selected_indices.end () && selected_indices.find (n) == selected_indices.end ()) {
|
|
std::swap (mp_data->free_files [n - 1], mp_data->free_files [n]);
|
|
selected_indices.erase (n - 1);
|
|
selected_indices.insert (n);
|
|
if (n_current == n - 1) {
|
|
n_current = n;
|
|
}
|
|
}
|
|
}
|
|
|
|
update ();
|
|
|
|
// select the new items
|
|
for (std::set <int>::const_iterator s = selected_indices.begin (); s != selected_indices.end (); ++s) {
|
|
tree->selectionModel ()->select (tree->model ()->index (*s, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows);
|
|
}
|
|
|
|
if (n_current >= 0) {
|
|
tree->selectionModel ()->select (mp_ui->layout_layers_tree->model ()->index (n_current, 0), QItemSelectionModel::Current | QItemSelectionModel::Rows);
|
|
}
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::free_layer_mapping_item_clicked (QTreeWidgetItem *item, int column)
|
|
{
|
|
if (column > 0) {
|
|
bool value = ! item->data (column, Qt::UserRole).toBool ();
|
|
item->setData (column, Qt::UserRole, value);
|
|
item->setData (column, Qt::DecorationRole, QVariant (QIcon (QString::fromUtf8 (value ? ":checked.png" : ":unchecked.png"))));
|
|
}
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::reset_free_mapping ()
|
|
{
|
|
QTreeWidget *tree = mp_ui->free_layer_mapping_tree;
|
|
QList<QTreeWidgetItem *> selected = tree->selectedItems ();
|
|
|
|
for (QList<QTreeWidgetItem *>::const_iterator s = selected.begin (); s != selected.end (); ++s) {
|
|
for (int column = 1; column <= int (mp_data->layout_layers.size ()); ++column) {
|
|
(*s)->setData (column, Qt::UserRole, false);
|
|
(*s)->setData (column, Qt::DecorationRole, QVariant (QIcon (QString::fromUtf8 (":unchecked.png"))));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::layout_layer_double_clicked (QTreeWidgetItem *, int)
|
|
{
|
|
QTreeWidget *tree = mp_data->free_layer_mapping ? mp_ui->free_layout_layers_tree : mp_ui->layout_layers_tree;
|
|
|
|
if (tree->currentItem ()) {
|
|
|
|
int n = tree->currentItem ()->data (0, Qt::UserRole).toInt ();
|
|
if (n >= 0 && n < int (mp_data->layout_layers.size ())) {
|
|
|
|
lay::NewLayerPropertiesDialog lp_dialog (this);
|
|
|
|
db::LayerProperties props = mp_data->layout_layers [n];
|
|
if (lp_dialog.exec_dialog (props)) {
|
|
mp_data->layout_layers [n] = props;
|
|
update ();
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
struct FilePositionCompare
|
|
{
|
|
bool operator() (const std::pair<db::GerberMetaData, std::string> &a, const std::pair<db::GerberMetaData, std::string> &b)
|
|
{
|
|
if ((a.first.cu_layer_number == 0) != (b.first.cu_layer_number == 0)) {
|
|
return (a.first.cu_layer_number == 0) < (b.first.cu_layer_number == 0);
|
|
}
|
|
if (a.first.cu_layer_number != b.first.cu_layer_number) {
|
|
return a.first.cu_layer_number < b.first.cu_layer_number;
|
|
}
|
|
if ((a.first.from_cu == 0) != (b.first.from_cu == 0)) {
|
|
return (a.first.from_cu == 0) < (b.first.from_cu == 0);
|
|
}
|
|
if (a.first.from_cu != b.first.from_cu) {
|
|
return a.first.from_cu < b.first.from_cu;
|
|
}
|
|
return a.second < b.second;
|
|
}
|
|
};
|
|
|
|
void
|
|
GerberImportDialog::enter_page ()
|
|
{
|
|
int page = mp_ui->central_stack->currentIndex ();
|
|
|
|
if (page == 5) {
|
|
|
|
// --- Free Files page
|
|
|
|
if (mp_data->free_files.empty ()) {
|
|
|
|
// scan the files in the directory and populate the file list
|
|
|
|
QDir dir (tl::to_qstring (mp_data->base_dir));
|
|
if (dir.exists ()) {
|
|
|
|
QStringList filters;
|
|
filters << tl::to_qstring ("*.gbr");
|
|
filters << tl::to_qstring ("*.GBR");
|
|
|
|
std::vector<std::pair<db::GerberMetaData, std::string> > files;
|
|
|
|
QStringList entries = dir.entryList (filters);
|
|
for (QStringList::const_iterator e = entries.begin (); e != entries.end (); ++e) {
|
|
db::GerberMetaData data = db::GerberImporter::scan (tl::to_string (dir.filePath (*e)));
|
|
files.push_back (std::make_pair (data, tl::to_string (*e)));
|
|
}
|
|
|
|
std::sort (files.begin (), files.end (), FilePositionCompare ());
|
|
|
|
if (files.empty ()) {
|
|
return;
|
|
}
|
|
if (QMessageBox::question (this, tr ("Populate Project"), tr ("Some files have been found in the specified base directory.\nIf these files contain file attributes, the project can be initialized properly.\n\nPopulate project from these files?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
|
|
return;
|
|
}
|
|
|
|
mp_data->layout_layers.clear ();
|
|
|
|
int min_layer = 0, max_layer = 0;
|
|
for (std::vector<std::pair<db::GerberMetaData, std::string> >::const_iterator f = files.begin (); f != files.end (); ++f) {
|
|
if (f->first.cu_layer_number > 0) {
|
|
if (min_layer == 0 || min_layer > f->first.cu_layer_number) {
|
|
min_layer = f->first.cu_layer_number;
|
|
}
|
|
if (max_layer == 0 || max_layer < f->first.cu_layer_number) {
|
|
max_layer = f->first.cu_layer_number;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::map<int, int> l2l;
|
|
std::map<int, int> l2v;
|
|
|
|
if (min_layer > 0) {
|
|
for (int l = min_layer; l <= max_layer; ++l) {
|
|
l2l.insert (std::make_pair (l, int (mp_data->layout_layers.size ())));
|
|
mp_data->layout_layers.push_back (db::LayerProperties (l * 2, 0, "Cu" + tl::to_string (l)));
|
|
if (l < max_layer) {
|
|
l2v.insert (std::make_pair (l, int (mp_data->layout_layers.size ())));
|
|
mp_data->layout_layers.push_back (db::LayerProperties (l * 2 + 1, 0, "Via" + tl::to_string (l)));
|
|
}
|
|
}
|
|
}
|
|
|
|
int next_layer = max_layer * 2;
|
|
int hole_num = 0, profile_num = 0, legend_num = 0, solder_num = 0;
|
|
|
|
for (std::vector<std::pair<db::GerberMetaData, std::string> >::const_iterator f = files.begin (); f != files.end (); ++f) {
|
|
|
|
mp_data->free_files.push_back (db::GerberFreeFileDescriptor ());
|
|
mp_data->free_files.back ().filename = tl::to_string (f->second);
|
|
|
|
std::vector<int> layers;
|
|
|
|
if (f->first.function == db::GerberMetaData::Copper) {
|
|
if (l2l.find (f->first.cu_layer_number) != l2l.end ()) {
|
|
layers.push_back (l2l [f->first.cu_layer_number]);
|
|
}
|
|
} else if (f->first.function == db::GerberMetaData::PlatedHole) {
|
|
for (int l = std::min (f->first.from_cu, f->first.to_cu); l < std::max (f->first.from_cu, f->first.to_cu); ++l) {
|
|
if (l2v.find (l) != l2v.end ()) {
|
|
layers.push_back (l2v [l]);
|
|
}
|
|
}
|
|
} else if (f->first.function == db::GerberMetaData::NonPlatedHole || f->first.function == db::GerberMetaData::NonPlatedHole) {
|
|
layers.push_back (int (mp_data->layout_layers.size ()));
|
|
mp_data->layout_layers.push_back (db::LayerProperties (++next_layer, 0, "Hole" + tl::to_string (++hole_num)));
|
|
} else if (f->first.function == db::GerberMetaData::Profile) {
|
|
layers.push_back (int (mp_data->layout_layers.size ()));
|
|
mp_data->layout_layers.push_back (db::LayerProperties (++next_layer, 0, "Profile" + tl::to_string (++profile_num)));
|
|
} else if (f->first.function == db::GerberMetaData::Legend) {
|
|
layers.push_back (int (mp_data->layout_layers.size ()));
|
|
mp_data->layout_layers.push_back (db::LayerProperties (++next_layer, 0, "Legend" + tl::to_string (++legend_num)));
|
|
} else if (f->first.function == db::GerberMetaData::SolderMask) {
|
|
layers.push_back (int (mp_data->layout_layers.size ()));
|
|
mp_data->layout_layers.push_back (db::LayerProperties (++next_layer, 0, "SolderMask" + tl::to_string (++solder_num)));
|
|
}
|
|
|
|
mp_data->free_files.back ().layout_layers = layers;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::commit_page ()
|
|
{
|
|
int page = mp_ui->central_stack->currentIndex ();
|
|
|
|
if (page == 0) {
|
|
|
|
// --- General page
|
|
mp_data->base_dir = tl::to_string (mp_ui->base_dir_le->text ());
|
|
mp_data->free_layer_mapping = mp_ui->free_mapping_cb->isChecked ();
|
|
if (mp_ui->import_into_rb->isChecked ()) {
|
|
mp_data->mode = db::GerberImportData::ModeIntoLayout;
|
|
} else if (mp_ui->import_new_panel_rb->isChecked ()) {
|
|
mp_data->mode = db::GerberImportData::ModeNewPanel;
|
|
} else if (mp_ui->import_same_panel_rb->isChecked ()) {
|
|
mp_data->mode = db::GerberImportData::ModeSamePanel;
|
|
}
|
|
|
|
} else if (page == 1) {
|
|
|
|
// --- Layout Layers page
|
|
// Nothing to commit here. It's done instantaneous.
|
|
|
|
if ((mp_data->layout_layers.size () % 2) == 0) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("The layout layer list must start and end with a metal layer")));
|
|
}
|
|
|
|
} else if (page == 2) {
|
|
|
|
if (mp_ui->mounting_cbx->currentIndex () == 0) {
|
|
mp_data->mounting = db::GerberImportData::MountingTop;
|
|
} else {
|
|
mp_data->mounting = db::GerberImportData::MountingBottom;
|
|
}
|
|
|
|
mp_data->num_metal_layers = -1;
|
|
mp_data->num_via_types = -1;
|
|
|
|
tl::from_string (tl::to_string (mp_ui->num_metal_le->text ()), mp_data->num_metal_layers);
|
|
tl::from_string (tl::to_string (mp_ui->num_via_le->text ()), mp_data->num_via_types);
|
|
|
|
if (mp_data->num_metal_layers < 0) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Invalid number of metal layers")));
|
|
}
|
|
if (mp_data->num_via_types < 0) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Invalid number of via layers")));
|
|
}
|
|
if (mp_data->num_metal_layers > int (mp_data->layout_layers.size () / 2 + 1)) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Not enough metal layer defined in layout layers to map the requested number of metal layers")));
|
|
}
|
|
|
|
if (int (mp_data->artwork_files.size ()) > mp_data->num_metal_layers) {
|
|
mp_data->artwork_files.erase (mp_data->artwork_files.begin () + mp_data->num_metal_layers, mp_data->artwork_files.end ());
|
|
} else {
|
|
while (int (mp_data->artwork_files.size ()) < mp_data->num_metal_layers) {
|
|
mp_data->artwork_files.push_back (db::GerberArtworkFileDescriptor ());
|
|
}
|
|
}
|
|
|
|
if (int (mp_data->drill_files.size ()) > mp_data->num_via_types) {
|
|
mp_data->drill_files.erase (mp_data->drill_files.begin () + mp_data->num_via_types, mp_data->drill_files.end ());
|
|
} else {
|
|
while (int (mp_data->drill_files.size ()) < mp_data->num_via_types) {
|
|
mp_data->drill_files.push_back (db::GerberDrillFileDescriptor ());
|
|
}
|
|
}
|
|
|
|
} else if (page == 3) {
|
|
|
|
// --- Artwork Files page
|
|
|
|
// Since we set the edit triggers to "currentChanged", this will commit the data:
|
|
mp_ui->artwork_files_tree->setCurrentIndex (QModelIndex ());
|
|
|
|
int n = 0;
|
|
for (std::vector <db::GerberArtworkFileDescriptor>::iterator l = mp_data->artwork_files.begin (); l != mp_data->artwork_files.end (); ++l, ++n) {
|
|
QTreeWidgetItem *item = mp_ui->artwork_files_tree->topLevelItem (n);
|
|
if (item) {
|
|
l->filename = tl::to_string (item->data (1, Qt::UserRole).toString ());
|
|
} else {
|
|
*l = db::GerberArtworkFileDescriptor ();
|
|
}
|
|
}
|
|
|
|
/* it might be a useful feature ...
|
|
for (std::vector <GerberArtworkFileDescriptor>::const_iterator l = mp_data->artwork_files.begin (); l != mp_data->artwork_files.end (); ++l) {
|
|
if (l->filename.empty ()) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Some file names are missing")));
|
|
}
|
|
}
|
|
*/
|
|
|
|
} else if (page == 4) {
|
|
|
|
// --- Drill Types And Files page
|
|
|
|
// Since we set the edit triggers to "currentChanged", this will commit the data:
|
|
mp_ui->drill_files_tree->setCurrentIndex (QModelIndex ());
|
|
|
|
int n = 0;
|
|
for (std::vector <db::GerberDrillFileDescriptor>::iterator l = mp_data->drill_files.begin (); l != mp_data->drill_files.end (); ++l, ++n) {
|
|
QTreeWidgetItem *item = mp_ui->drill_files_tree->topLevelItem (n);
|
|
if (item) {
|
|
l->start = item->data (1, Qt::UserRole).toInt ();
|
|
l->stop = item->data (2, Qt::UserRole).toInt ();
|
|
if (l->stop <= l->start) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Stop layers must be past start layers")));
|
|
}
|
|
l->filename = tl::to_string (item->data (3, Qt::UserRole).toString ());
|
|
} else {
|
|
*l = db::GerberDrillFileDescriptor ();
|
|
}
|
|
}
|
|
|
|
for (std::vector <db::GerberDrillFileDescriptor>::const_iterator l = mp_data->drill_files.begin (); l != mp_data->drill_files.end (); ++l) {
|
|
/* it might be a useful feature ...
|
|
if (l->filename.empty ()) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Some file names are missing")));
|
|
}
|
|
*/
|
|
if (l->start < 0) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Some start layer specifications are missing")));
|
|
}
|
|
if (l->stop < 0) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Some stop layer specifications are missing")));
|
|
}
|
|
}
|
|
|
|
} else if (page == 5) {
|
|
|
|
// --- Free Files page
|
|
// Since we set the edit triggers to "currentChanged", this will commit the data:
|
|
mp_ui->free_files_tree->setCurrentIndex (QModelIndex ());
|
|
|
|
int n = 0;
|
|
for (std::vector <db::GerberFreeFileDescriptor>::iterator l = mp_data->free_files.begin (); l != mp_data->free_files.end (); ++l, ++n) {
|
|
QTreeWidgetItem *item = mp_ui->free_files_tree->topLevelItem (n);
|
|
if (item) {
|
|
l->filename = tl::to_string (item->data (0, Qt::UserRole).toString ());
|
|
} else {
|
|
*l = db::GerberFreeFileDescriptor ();
|
|
}
|
|
}
|
|
|
|
/* it might be a useful feature ...
|
|
for (std::vector <GerberFreeFileDescriptor>::iterator l = mp_data->free_files.begin (); l != mp_data->free_files.end (); ++l, ++n) {
|
|
if (l->filename.empty ()) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Some file names are missing")));
|
|
}
|
|
}
|
|
*/
|
|
|
|
// add layers for all free files if no layer is defined yet. Add additional layers. Try to find some useful numbering scheme.
|
|
|
|
int max_layer = 0;
|
|
for (std::vector <db::LayerProperties>::const_iterator l = mp_data->layout_layers.begin (); l != mp_data->layout_layers.end (); ++l) {
|
|
max_layer = std::max (max_layer, l->layer);
|
|
}
|
|
|
|
for (size_t i = 0; i < mp_data->free_files.size (); ++i) {
|
|
|
|
std::vector<int> valid_layers;
|
|
for (std::vector<int>::const_iterator l = mp_data->free_files[i].layout_layers.begin (); l != mp_data->free_files[i].layout_layers.end (); ++l) {
|
|
if (*l >= 0 && *l < int (mp_data->layout_layers.size ())) {
|
|
valid_layers.push_back (*l);
|
|
}
|
|
}
|
|
|
|
mp_data->free_files[i].layout_layers = valid_layers;
|
|
|
|
// Add a stupid 1:1 mapping if no layers are mapped for the next file.
|
|
if (valid_layers.empty ()) {
|
|
|
|
mp_data->free_files[i].layout_layers.push_back (int (mp_data->layout_layers.size ()));
|
|
|
|
mp_data->layout_layers.push_back (db::LayerProperties ());
|
|
mp_data->layout_layers.back ().layer = ++max_layer;
|
|
mp_data->layout_layers.back ().datatype = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (page == 6) {
|
|
|
|
// --- Free Layout Layers page
|
|
// no commit needed - done immediately
|
|
|
|
// reset any layers not present any longer
|
|
for (std::vector <db::GerberFreeFileDescriptor>::iterator l = mp_data->free_files.begin (); l != mp_data->free_files.end (); ++l) {
|
|
std::vector <int> indices;
|
|
for (std::vector <int>::const_iterator i = l->layout_layers.begin (); i != l->layout_layers.end (); ++i) {
|
|
if (*i < int (mp_data->layout_layers.size ())) {
|
|
indices.push_back (*i);
|
|
}
|
|
}
|
|
l->layout_layers = indices;
|
|
}
|
|
|
|
} else if (page == 7) {
|
|
|
|
// --- Free Files And Layer Mapping page
|
|
// Since we set the edit triggers to "currentChanged", this will commit the data:
|
|
mp_ui->free_layer_mapping_tree->setCurrentIndex (QModelIndex ());
|
|
|
|
int n = 0;
|
|
for (std::vector <db::GerberFreeFileDescriptor>::iterator l = mp_data->free_files.begin (); l != mp_data->free_files.end (); ++l, ++n) {
|
|
QTreeWidgetItem *item = mp_ui->free_layer_mapping_tree->topLevelItem (n);
|
|
if (item) {
|
|
|
|
l->filename = tl::to_string (item->data (0, Qt::UserRole).toString ());
|
|
|
|
std::vector <int> indices;
|
|
for (int i = 0; i < int (mp_data->layout_layers.size ()); ++i) {
|
|
if (item->data (i + 1, Qt::UserRole).toBool ()) {
|
|
indices.push_back (i);
|
|
}
|
|
}
|
|
l->layout_layers = indices;
|
|
|
|
} else {
|
|
*l = db::GerberFreeFileDescriptor ();
|
|
}
|
|
}
|
|
|
|
/* it might be a useful feature ...
|
|
for (std::vector <GerberFreeFileDescriptor>::iterator l = mp_data->free_layer_mapping_tree.begin (); l != mp_data->free_layer_mapping_tree.end (); ++l, ++n) {
|
|
if (l->filename.empty ()) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Some file names are missing")));
|
|
}
|
|
}
|
|
*/
|
|
|
|
} else if (page == 8) {
|
|
|
|
// --- Coordinate Mapping page
|
|
QLineEdit *(coord_editors[][4]) = {
|
|
{ mp_ui->pcb_x1_le, mp_ui->pcb_y1_le, mp_ui->layout_x1_le, mp_ui->layout_y1_le },
|
|
{ mp_ui->pcb_x2_le, mp_ui->pcb_y2_le, mp_ui->layout_x2_le, mp_ui->layout_y2_le },
|
|
{ mp_ui->pcb_x3_le, mp_ui->pcb_y3_le, mp_ui->layout_x3_le, mp_ui->layout_y3_le }
|
|
};
|
|
|
|
mp_data->reference_points.clear ();
|
|
for (unsigned int i = 0; i < sizeof (coord_editors) / sizeof (coord_editors [0]); ++i) {
|
|
|
|
std::string t_pcb_x (tl::to_string (coord_editors [i][0]->text ()));
|
|
tl::Extractor pcb_x (t_pcb_x.c_str ());
|
|
|
|
std::string t_pcb_y (tl::to_string (coord_editors [i][1]->text ()));
|
|
tl::Extractor pcb_y (t_pcb_y.c_str ());
|
|
|
|
std::string t_layout_x (tl::to_string (coord_editors [i][2]->text ()));
|
|
tl::Extractor layout_x (t_layout_x.c_str ());
|
|
|
|
std::string t_layout_y (tl::to_string (coord_editors [i][3]->text ()));
|
|
tl::Extractor layout_y (t_layout_y.c_str ());
|
|
|
|
if (pcb_x.at_end () || pcb_y.at_end () || layout_x.at_end () || layout_y.at_end ()) {
|
|
|
|
if (! pcb_x.at_end () || ! pcb_y.at_end () || ! layout_x.at_end () || ! layout_y.at_end ()) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("All coordinates (PCB and layout) must be specified for a reference point")));
|
|
}
|
|
|
|
} else {
|
|
|
|
double x, y;
|
|
|
|
pcb_x.read (x);
|
|
pcb_x.expect_end ();
|
|
pcb_y.read (y);
|
|
pcb_y.expect_end ();
|
|
db::DPoint pcb (x, y);
|
|
|
|
layout_x.read (x);
|
|
layout_x.expect_end ();
|
|
layout_y.read (y);
|
|
layout_y.expect_end ();
|
|
db::DPoint layout (x, y);
|
|
|
|
mp_data->reference_points.push_back (std::make_pair (pcb, layout));
|
|
|
|
}
|
|
}
|
|
|
|
std::string t (tl::to_string (mp_ui->explicit_trans_le->text ()));
|
|
tl::Extractor ex (t.c_str ());
|
|
mp_data->explicit_trans = db::DCplxTrans ();
|
|
if (! ex.at_end ()) {
|
|
ex.read (mp_data->explicit_trans);
|
|
ex.expect_end ();
|
|
}
|
|
|
|
} else if (page == 9) {
|
|
|
|
// --- Options page
|
|
mp_data->layer_properties_file = tl::to_string (mp_ui->layer_properties_file_le->text ());
|
|
|
|
std::string t (tl::to_string (mp_ui->circle_points_le->text ()));
|
|
tl::Extractor ex (t.c_str ());
|
|
if (! ex.at_end ()) {
|
|
ex.read (mp_data->num_circle_points);
|
|
ex.expect_end ();
|
|
if (mp_data->num_circle_points < 4) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Number of points per circle must be 4 at least")));
|
|
}
|
|
} else {
|
|
mp_data->num_circle_points = -1;
|
|
}
|
|
|
|
mp_data->merge_flag = mp_ui->merge_cb->isChecked ();
|
|
mp_data->invert_negative_layers = mp_ui->invert_cb->isChecked ();
|
|
tl::from_string (tl::to_string (mp_ui->border_le->text ()), mp_data->border);
|
|
|
|
bool import_into = (mp_data->mode == db::GerberImportData::ModeIntoLayout);
|
|
if (! import_into) {
|
|
|
|
tl::from_string (tl::to_string (mp_ui->dbu_le->text ()), mp_data->dbu);
|
|
if (mp_data->dbu < 1e-6) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Database unit must not be negative or zero")));
|
|
}
|
|
|
|
mp_data->topcell_name = tl::to_string (mp_ui->topcell_le->text ());
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
GerberImportDialog::update ()
|
|
{
|
|
int n, nn;
|
|
|
|
std::string section_headers[] = {
|
|
tl::to_string (QObject::tr ("General")),
|
|
tl::to_string (QObject::tr ("Layout Layers")),
|
|
tl::to_string (QObject::tr ("Layer Stack")),
|
|
tl::to_string (QObject::tr ("Artwork Files")),
|
|
tl::to_string (QObject::tr ("Drill Types And Files")),
|
|
tl::to_string (QObject::tr ("Files")),
|
|
tl::to_string (QObject::tr ("Layout Layers")),
|
|
tl::to_string (QObject::tr ("Layer Mapping")),
|
|
tl::to_string (QObject::tr ("Coordinate Mapping")),
|
|
tl::to_string (QObject::tr ("Options"))
|
|
};
|
|
|
|
int page = mp_ui->central_stack->currentIndex ();
|
|
if (page < 0 || page >= int (sizeof (section_headers) / sizeof (section_headers [0]))) {
|
|
return;
|
|
}
|
|
|
|
mp_ui->last_pb->setEnabled (page > 0);
|
|
mp_ui->next_pb->setEnabled (page < int (sizeof (next_pages_stacked) / sizeof (next_pages_stacked [0]) - 1));
|
|
mp_ui->section_header_lbl->setText (tl::to_qstring (section_headers [page]));
|
|
|
|
// --- General page
|
|
mp_ui->base_dir_le->setText (tl::to_qstring (mp_data->base_dir));
|
|
mp_ui->free_mapping_cb->setChecked (mp_data->free_layer_mapping);
|
|
mp_ui->import_into_rb->setChecked (mp_data->mode == db::GerberImportData::ModeIntoLayout);
|
|
mp_ui->import_new_panel_rb->setChecked (mp_data->mode == db::GerberImportData::ModeNewPanel);
|
|
mp_ui->import_same_panel_rb->setChecked (mp_data->mode == db::GerberImportData::ModeSamePanel);
|
|
|
|
// --- Layout Layers page (stacked)
|
|
mp_ui->layout_layers_tree->clear ();
|
|
n = 0;
|
|
nn = mp_ui->layout_layers_tree->topLevelItemCount ();
|
|
for (std::vector <db::LayerProperties>::const_iterator l = mp_data->layout_layers.begin (); l != mp_data->layout_layers.end (); ++l, ++n) {
|
|
|
|
QTreeWidgetItem *item;
|
|
if (n < nn) {
|
|
item = mp_ui->layout_layers_tree->topLevelItem (n);
|
|
} else {
|
|
item = new QTreeWidgetItem (mp_ui->layout_layers_tree);
|
|
mp_ui->layout_layers_tree->addTopLevelItem (item);
|
|
}
|
|
|
|
std::string label;
|
|
if ((n % 2) == 0) {
|
|
label = tl::sprintf (tl::to_string (QObject::tr ("Metal %d")), n / 2 + 1);
|
|
} else {
|
|
label = tl::sprintf (tl::to_string (QObject::tr ("Via %d-%d")), (n - 1) / 2 + 1, (n - 1) / 2 + 2);
|
|
}
|
|
|
|
item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (label)));
|
|
item->setData (0, Qt::UserRole, QVariant (n));
|
|
|
|
item->setData (1, Qt::DisplayRole, QVariant (tl::to_qstring (l->to_string ())));
|
|
|
|
}
|
|
|
|
while (mp_ui->layout_layers_tree->topLevelItemCount () > n) {
|
|
delete mp_ui->layout_layers_tree->topLevelItem (n);
|
|
}
|
|
|
|
mp_ui->layout_layers_tree->clearSelection ();
|
|
|
|
// --- Layer Stack page (stacked)
|
|
mp_ui->mounting_cbx->setCurrentIndex (mp_data->mounting == db::GerberImportData::MountingTop ? 0 : 1);
|
|
mp_ui->num_metal_le->setText (tl::to_qstring (tl::to_string (mp_data->num_metal_layers)));
|
|
mp_ui->num_via_le->setText (tl::to_qstring (tl::to_string (mp_data->num_via_types)));
|
|
|
|
// --- Artwork Files page (stacked)
|
|
mp_ui->artwork_files_tree->clear ();
|
|
n = 0;
|
|
for (std::vector <db::GerberArtworkFileDescriptor>::const_iterator l = mp_data->artwork_files.begin (); l != mp_data->artwork_files.end (); ++l, ++n) {
|
|
|
|
QTreeWidgetItem *item = new QTreeWidgetItem (mp_ui->artwork_files_tree);
|
|
item->setFlags (item->flags () | Qt::ItemIsEditable);
|
|
|
|
std::string label;
|
|
label = tl::sprintf (tl::to_string (QObject::tr ("File %d")), n + 1);
|
|
if (n == 0) {
|
|
label += tl::to_string (QObject::tr (" (Top)"));
|
|
} else if (n == int (mp_data->artwork_files.size () - 1)) {
|
|
label += tl::to_string (QObject::tr (" (Bottom)"));
|
|
}
|
|
|
|
item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (label)));
|
|
item->setData (0, Qt::UserRole, QVariant (n));
|
|
|
|
if (! l->filename.empty ()) {
|
|
|
|
item->setData (1, Qt::DisplayRole, QVariant (tl::to_qstring (l->filename)));
|
|
|
|
QFileInfo file_info (tl::to_qstring (l->filename));
|
|
if (! mp_data->base_dir.empty () && ! file_info.isAbsolute ()) {
|
|
file_info = QFileInfo (QDir (tl::to_qstring (mp_data->base_dir)), tl::to_qstring (l->filename));
|
|
}
|
|
|
|
if (file_info.exists () && file_info.isReadable ()) {
|
|
item->setData (1, Qt::ForegroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Active, QPalette::Text));
|
|
item->setData (1, Qt::BackgroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Active, QPalette::Base));
|
|
} else {
|
|
item->setData (1, Qt::ForegroundRole, QColor (Qt::red));
|
|
item->setData (1, Qt::BackgroundRole, QColor (Qt::red).lighter (180));
|
|
}
|
|
|
|
} else {
|
|
item->setData (1, Qt::DisplayRole, QVariant (QObject::tr ("Click here to enter file name")));
|
|
item->setData (1, Qt::ForegroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Disabled, QPalette::Text));
|
|
item->setData (1, Qt::BackgroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Disabled, QPalette::Base));
|
|
}
|
|
|
|
item->setData (1, Qt::UserRole, QVariant (tl::to_qstring (l->filename)));
|
|
|
|
mp_ui->artwork_files_tree->addTopLevelItem (item);
|
|
|
|
}
|
|
|
|
// --- Drill Types And Files page (stacked)
|
|
mp_ui->drill_files_tree->clear ();
|
|
n = 0;
|
|
for (std::vector <db::GerberDrillFileDescriptor>::const_iterator l = mp_data->drill_files.begin (); l != mp_data->drill_files.end (); ++l, ++n) {
|
|
|
|
QTreeWidgetItem *item = new QTreeWidgetItem (mp_ui->drill_files_tree);
|
|
item->setFlags (item->flags () | Qt::ItemIsEditable);
|
|
|
|
std::string label;
|
|
label = tl::sprintf (tl::to_string (QObject::tr ("File %d")), n + 1);
|
|
|
|
item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (label)));
|
|
item->setData (0, Qt::UserRole, QVariant (n));
|
|
|
|
if (l->start >= 0) {
|
|
std::string start = tl::sprintf (tl::to_string (QObject::tr ("Metal %d")), l->start + 1);
|
|
item->setData (1, Qt::DisplayRole, QVariant (tl::to_qstring (start)));
|
|
item->setData (1, Qt::ForegroundRole, mp_ui->drill_files_tree->palette ().color (QPalette::Active, QPalette::Text));
|
|
} else {
|
|
item->setData (1, Qt::DisplayRole, QVariant (QString::fromUtf8 ("...")));
|
|
item->setData (1, Qt::ForegroundRole, mp_ui->drill_files_tree->palette ().color (QPalette::Disabled, QPalette::Text));
|
|
}
|
|
item->setData (1, Qt::UserRole, QVariant (l->start));
|
|
|
|
if (l->stop >= 0) {
|
|
std::string stop = tl::sprintf (tl::to_string (QObject::tr ("Metal %d")), l->stop + 1);
|
|
item->setData (2, Qt::DisplayRole, QVariant (tl::to_qstring (stop)));
|
|
item->setData (2, Qt::ForegroundRole, mp_ui->drill_files_tree->palette ().color (QPalette::Active, QPalette::Text));
|
|
} else {
|
|
item->setData (2, Qt::DisplayRole, QVariant (QString::fromUtf8 ("...")));
|
|
item->setData (2, Qt::ForegroundRole, mp_ui->drill_files_tree->palette ().color (QPalette::Disabled, QPalette::Text));
|
|
}
|
|
item->setData (2, Qt::UserRole, QVariant (l->stop));
|
|
|
|
if (! l->filename.empty ()) {
|
|
|
|
item->setData (3, Qt::DisplayRole, QVariant (tl::to_qstring (l->filename)));
|
|
|
|
QFileInfo file_info (tl::to_qstring (l->filename));
|
|
if (! mp_data->base_dir.empty () && ! file_info.isAbsolute ()) {
|
|
file_info = QFileInfo (QDir (tl::to_qstring (mp_data->base_dir)), tl::to_qstring (l->filename));
|
|
}
|
|
|
|
if (file_info.exists () && file_info.isReadable ()) {
|
|
item->setData (3, Qt::ForegroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Active, QPalette::Text));
|
|
item->setData (3, Qt::BackgroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Active, QPalette::Base));
|
|
} else {
|
|
item->setData (3, Qt::ForegroundRole, QColor (Qt::red));
|
|
item->setData (3, Qt::BackgroundRole, QColor (Qt::red).lighter (180));
|
|
}
|
|
|
|
} else {
|
|
item->setData (3, Qt::DisplayRole, QVariant (QObject::tr ("Click here to enter file name")));
|
|
item->setData (3, Qt::ForegroundRole, mp_ui->drill_files_tree->palette ().color (QPalette::Disabled, QPalette::Text));
|
|
item->setData (3, Qt::BackgroundRole, mp_ui->drill_files_tree->palette ().color (QPalette::Disabled, QPalette::Base));
|
|
}
|
|
|
|
item->setData (3, Qt::UserRole, QVariant (tl::to_qstring (l->filename)));
|
|
|
|
mp_ui->drill_files_tree->addTopLevelItem (item);
|
|
|
|
}
|
|
|
|
// --- Files page (free)
|
|
mp_ui->free_files_tree->clear ();
|
|
n = 0;
|
|
for (std::vector <db::GerberFreeFileDescriptor>::const_iterator l = mp_data->free_files.begin (); l != mp_data->free_files.end (); ++l, ++n) {
|
|
|
|
QTreeWidgetItem *item = new QTreeWidgetItem (mp_ui->free_files_tree);
|
|
item->setFlags (item->flags () | Qt::ItemIsEditable);
|
|
|
|
item->setData (0, Qt::UserRole + 1, QVariant (n));
|
|
|
|
if (! l->filename.empty ()) {
|
|
|
|
item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (l->filename)));
|
|
|
|
QFileInfo file_info (tl::to_qstring (l->filename));
|
|
if (! mp_data->base_dir.empty () && ! file_info.isAbsolute ()) {
|
|
file_info = QFileInfo (QDir (tl::to_qstring (mp_data->base_dir)), tl::to_qstring (l->filename));
|
|
}
|
|
|
|
if (file_info.exists () && file_info.isReadable ()) {
|
|
item->setData (0, Qt::ForegroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Active, QPalette::Text));
|
|
item->setData (0, Qt::BackgroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Active, QPalette::Base));
|
|
} else {
|
|
item->setData (0, Qt::ForegroundRole, QColor (Qt::red));
|
|
item->setData (0, Qt::BackgroundRole, QColor (Qt::red).lighter (180));
|
|
}
|
|
|
|
} else {
|
|
item->setData (0, Qt::DisplayRole, QVariant (QObject::tr ("Click here to enter file name")));
|
|
item->setData (0, Qt::ForegroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Disabled, QPalette::Text));
|
|
item->setData (0, Qt::BackgroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Disabled, QPalette::Base));
|
|
}
|
|
|
|
item->setData (0, Qt::UserRole, QVariant (tl::to_qstring (l->filename)));
|
|
|
|
mp_ui->free_files_tree->addTopLevelItem (item);
|
|
|
|
}
|
|
|
|
// --- Layout Layers page (free)
|
|
mp_ui->free_layout_layers_tree->clear (); // TODO: check whether this is a good solution and simplify the scheme below
|
|
n = 0;
|
|
nn = mp_ui->free_layout_layers_tree->topLevelItemCount ();
|
|
for (std::vector <db::LayerProperties>::const_iterator l = mp_data->layout_layers.begin (); l != mp_data->layout_layers.end (); ++l, ++n) {
|
|
|
|
QTreeWidgetItem *item;
|
|
if (n < nn) {
|
|
item = mp_ui->free_layout_layers_tree->topLevelItem (n);
|
|
} else {
|
|
item = new QTreeWidgetItem (mp_ui->free_layout_layers_tree);
|
|
mp_ui->free_layout_layers_tree->addTopLevelItem (item);
|
|
}
|
|
|
|
item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (l->to_string ())));
|
|
item->setData (0, Qt::UserRole, QVariant (n));
|
|
|
|
}
|
|
|
|
while (mp_ui->free_layout_layers_tree->topLevelItemCount () > n) {
|
|
delete mp_ui->free_layout_layers_tree->topLevelItem (n);
|
|
}
|
|
|
|
mp_ui->free_layout_layers_tree->clearSelection ();
|
|
|
|
// --- Files And Layer Mapping page (free)
|
|
mp_ui->free_layer_mapping_tree->clear ();
|
|
n = 0;
|
|
for (std::vector <db::GerberFreeFileDescriptor>::const_iterator l = mp_data->free_files.begin (); l != mp_data->free_files.end (); ++l, ++n) {
|
|
|
|
QTreeWidgetItem *item = new QTreeWidgetItem (mp_ui->free_layer_mapping_tree);
|
|
item->setFlags (item->flags () | Qt::ItemIsEditable);
|
|
|
|
item->setData (0, Qt::UserRole + 1, QVariant (n));
|
|
|
|
if (! l->filename.empty ()) {
|
|
|
|
item->setData (0, Qt::DisplayRole, QVariant (tl::to_qstring (l->filename)));
|
|
item->setData (0, Qt::ToolTipRole, QVariant (tl::to_qstring (l->filename)));
|
|
|
|
QFileInfo file_info (tl::to_qstring (l->filename));
|
|
if (! mp_data->base_dir.empty () && ! file_info.isAbsolute ()) {
|
|
file_info = QFileInfo (QDir (tl::to_qstring (mp_data->base_dir)), tl::to_qstring (l->filename));
|
|
}
|
|
|
|
if (file_info.exists () && file_info.isReadable ()) {
|
|
item->setData (0, Qt::ForegroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Active, QPalette::Text));
|
|
item->setData (0, Qt::BackgroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Active, QPalette::Base));
|
|
} else {
|
|
item->setData (0, Qt::ForegroundRole, QColor (Qt::red));
|
|
item->setData (0, Qt::BackgroundRole, QColor (Qt::red).lighter (180));
|
|
}
|
|
|
|
} else {
|
|
item->setData (0, Qt::DisplayRole, QVariant (QObject::tr ("Click here to enter file name")));
|
|
item->setData (0, Qt::ForegroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Disabled, QPalette::Text));
|
|
item->setData (0, Qt::BackgroundRole, mp_ui->artwork_files_tree->palette ().color (QPalette::Disabled, QPalette::Base));
|
|
}
|
|
|
|
item->setData (0, Qt::UserRole, QVariant (tl::to_qstring (l->filename)));
|
|
|
|
for (std::vector <db::LayerProperties>::iterator ll = mp_data->layout_layers.begin (); ll != mp_data->layout_layers.end (); ++ll) {
|
|
|
|
bool is_present = false;
|
|
int layer = int (std::distance (mp_data->layout_layers.begin (), ll));
|
|
for (std::vector <int>::const_iterator i = l->layout_layers.begin (); i != l->layout_layers.end () && ! is_present; ++i) {
|
|
is_present = (*i == layer);
|
|
}
|
|
|
|
item->setData (layer + 1, Qt::UserRole, QVariant (is_present));
|
|
item->setData (layer + 1, Qt::DecorationRole, QVariant (QIcon (QString::fromUtf8 (is_present ? ":checked.png" : ":unchecked.png"))));
|
|
|
|
}
|
|
|
|
mp_ui->free_layer_mapping_tree->addTopLevelItem (item);
|
|
|
|
}
|
|
|
|
mp_ui->free_layer_mapping_tree->setColumnCount (int (mp_data->layout_layers.size () + 1));
|
|
n = 0;
|
|
mp_ui->free_layer_mapping_tree->headerItem ()->setData (0, Qt::DisplayRole, QVariant (QObject::tr ("File")));
|
|
for (std::vector <db::LayerProperties>::const_iterator l = mp_data->layout_layers.begin (); l != mp_data->layout_layers.end (); ++l, ++n) {
|
|
|
|
QString hdr_label;
|
|
|
|
db::LayerProperties ll = *l;
|
|
ll.name.clear ();
|
|
hdr_label = tl::to_qstring (ll.to_string ());
|
|
hdr_label += QString::fromUtf8 ("\n");
|
|
|
|
if (l->name.size () > 4) {
|
|
hdr_label += tl::to_qstring (std::string (l->name, 0, 4) + "...");
|
|
} else {
|
|
hdr_label += tl::to_qstring (l->name);
|
|
}
|
|
|
|
mp_ui->free_layer_mapping_tree->headerItem ()->setData (n + 1, Qt::DisplayRole, QVariant (hdr_label));
|
|
mp_ui->free_layer_mapping_tree->headerItem ()->setData (n + 1, Qt::ToolTipRole, QVariant (tl::to_qstring (l->to_string ())));
|
|
|
|
if (mp_ui->free_layer_mapping_tree->itemDelegateForColumn (n + 1) == 0) {
|
|
mp_ui->free_layer_mapping_tree->setItemDelegateForColumn (n + 1, new GerberImportDialogNoEditDelegate (mp_ui->free_layer_mapping_tree));
|
|
}
|
|
|
|
#if QT_VERSION >= 0x050000
|
|
mp_ui->free_layer_mapping_tree->header ()->setSectionResizeMode (n + 1, QHeaderView::ResizeToContents);
|
|
#else
|
|
mp_ui->free_layer_mapping_tree->header ()->setResizeMode (n + 1, QHeaderView::ResizeToContents);
|
|
#endif
|
|
|
|
}
|
|
|
|
// --- Coordinate Mapping page
|
|
QLineEdit *(coord_editors[][4]) = {
|
|
{ mp_ui->pcb_x1_le, mp_ui->pcb_y1_le, mp_ui->layout_x1_le, mp_ui->layout_y1_le },
|
|
{ mp_ui->pcb_x2_le, mp_ui->pcb_y2_le, mp_ui->layout_x2_le, mp_ui->layout_y2_le },
|
|
{ mp_ui->pcb_x3_le, mp_ui->pcb_y3_le, mp_ui->layout_x3_le, mp_ui->layout_y3_le }
|
|
};
|
|
|
|
for (unsigned int i = 0; i < sizeof (coord_editors) / sizeof (coord_editors [0]); ++i) {
|
|
if (mp_data->reference_points.size () > i) {
|
|
coord_editors[i][0]->setText (tl::to_qstring (tl::to_string (mp_data->reference_points [i].first.x ())));
|
|
coord_editors[i][1]->setText (tl::to_qstring (tl::to_string (mp_data->reference_points [i].first.y ())));
|
|
coord_editors[i][2]->setText (tl::to_qstring (tl::to_string (mp_data->reference_points [i].second.x ())));
|
|
coord_editors[i][3]->setText (tl::to_qstring (tl::to_string (mp_data->reference_points [i].second.y ())));
|
|
} else {
|
|
for (unsigned int j = 0; j < 4; ++j) {
|
|
coord_editors[i][j]->setText (QString ());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mp_data->explicit_trans == db::DCplxTrans ()) {
|
|
mp_ui->explicit_trans_le->setText (QString ());
|
|
} else {
|
|
mp_ui->explicit_trans_le->setText (tl::to_qstring (mp_data->explicit_trans.to_string ()));
|
|
}
|
|
|
|
// --- Options page
|
|
mp_ui->layer_properties_file_le->setText (tl::to_qstring (mp_data->layer_properties_file));
|
|
if (mp_data->num_circle_points < 4) {
|
|
mp_ui->circle_points_le->setText (QString ());
|
|
} else {
|
|
mp_ui->circle_points_le->setText (tl::to_qstring (tl::to_string (mp_data->num_circle_points)));
|
|
}
|
|
|
|
mp_ui->merge_cb->setChecked (mp_data->merge_flag);
|
|
mp_ui->invert_cb->setChecked (mp_data->invert_negative_layers);
|
|
mp_ui->border_le->setText (tl::to_qstring (tl::to_string (mp_data->border)));
|
|
|
|
bool import_into = (mp_data->mode == db::GerberImportData::ModeIntoLayout);
|
|
if (import_into) {
|
|
mp_ui->dbu_le->setText (QString ());
|
|
mp_ui->topcell_le->setText (QString ());
|
|
} else {
|
|
mp_ui->dbu_le->setText (tl::to_qstring (tl::to_string (mp_data->dbu)));
|
|
mp_ui->topcell_le->setText (tl::to_qstring (mp_data->topcell_name));
|
|
}
|
|
|
|
// In "into layout" mode, the top cell and database unit are given by the current layout and cannot be
|
|
// modified.
|
|
mp_ui->dbu_le->setEnabled (! import_into);
|
|
mp_ui->dbu_lbl1->setEnabled (! import_into);
|
|
mp_ui->dbu_lbl2->setEnabled (! import_into);
|
|
mp_ui->topcell_le->setEnabled (! import_into);
|
|
mp_ui->topcell_lbl->setEnabled (! import_into);
|
|
}
|
|
|
|
}
|
|
|