Merge pull request #729 from KLayout/search-improvements

Search improvements
This commit is contained in:
Matthias Köfferlein 2021-02-25 21:27:25 +01:00 committed by GitHub
commit 9d5636a89d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1253 additions and 602 deletions

View File

@ -134,7 +134,7 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2)
try {
tl::from_string (tl::to_string (x1->text ()), dx1);
lay::indicate_error (x1, 0);
lay::indicate_error (x1, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x1, &ex);
has_error = true;
@ -142,7 +142,7 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2)
try {
tl::from_string (tl::to_string (x2->text ()), dx2);
lay::indicate_error (x2, 0);
lay::indicate_error (x2, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x2, &ex);
has_error = true;
@ -150,7 +150,7 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2)
try {
tl::from_string (tl::to_string (y1->text ()), dy1);
lay::indicate_error (y1, 0);
lay::indicate_error (y1, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y1, &ex);
has_error = true;
@ -158,7 +158,7 @@ PropertiesPage::get_points (db::DPoint &p1, db::DPoint &p2)
try {
tl::from_string (tl::to_string (y2->text ()), dy2);
lay::indicate_error (y2, 0);
lay::indicate_error (y2, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y2, &ex);
has_error = true;

View File

@ -60,7 +60,7 @@ static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le
Value value = Value (0);
tl::from_string (tl::to_string (le->text ()), value);
dispatcher->config_set (cfg_name, tl::to_string (value));
lay::indicate_error (le, 0);
lay::indicate_error (le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
}
@ -114,7 +114,7 @@ EditorOptionsGeneric::apply (lay::Dispatcher *root)
try {
db::DVector eg;
egc.from_string_picky (tl::to_string (mp_ui->edit_grid_le->text ()), eg);
lay::indicate_error (mp_ui->edit_grid_le, 0);
lay::indicate_error (mp_ui->edit_grid_le, (tl::Exception *) 0);
root->config_set (cfg_edit_grid, egc.to_string (eg));
} catch (tl::Exception &ex) {
lay::indicate_error (mp_ui->edit_grid_le, &ex);
@ -166,7 +166,7 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root)
mp_ui->edit_grid_le->setText (tl::to_qstring (egc.to_string (eg)));
}
grid_changed (mp_ui->grid_cb->currentIndex ());
lay::indicate_error (mp_ui->edit_grid_le, 0);
lay::indicate_error (mp_ui->edit_grid_le, (tl::Exception *) 0);
// edit & move angle
@ -196,7 +196,7 @@ EditorOptionsGeneric::setup (lay::Dispatcher *root)
unsigned int max_shapes = 1000;
root->config_get (cfg_edit_max_shapes_of_instances, max_shapes);
mp_ui->max_shapes_le->setText (tl::to_qstring (tl::to_string (max_shapes)));
lay::indicate_error (mp_ui->max_shapes_le, 0);
lay::indicate_error (mp_ui->max_shapes_le, (tl::Exception *) 0);
bool show_shapes = true;
root->config_get (cfg_edit_show_shapes_of_instances, show_shapes);
@ -356,7 +356,7 @@ EditorOptionsPath::setup (lay::Dispatcher *root)
double w = 0.0;
root->config_get (cfg_edit_path_width, w);
mp_ui->width_le->setText (tl::to_qstring (tl::to_string (w)));
lay::indicate_error (mp_ui->width_le, 0);
lay::indicate_error (mp_ui->width_le, (tl::Exception *) 0);
// path type and extensions
@ -377,9 +377,9 @@ EditorOptionsPath::setup (lay::Dispatcher *root)
root->config_get (cfg_edit_path_ext_var_begin, bgnext);
root->config_get (cfg_edit_path_ext_var_end, endext);
mp_ui->start_ext_le->setText (tl::to_qstring (tl::to_string (bgnext)));
lay::indicate_error (mp_ui->start_ext_le, 0);
lay::indicate_error (mp_ui->start_ext_le, (tl::Exception *) 0);
mp_ui->end_ext_le->setText (tl::to_qstring (tl::to_string (endext)));
lay::indicate_error (mp_ui->end_ext_le, 0);
lay::indicate_error (mp_ui->end_ext_le, (tl::Exception *) 0);
}
// ------------------------------------------------------------------
@ -631,7 +631,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
double angle = 0.0;
root->config_get (cfg_edit_inst_angle, angle);
mp_ui->angle_le->setText (tl::to_qstring (tl::to_string (angle)));
lay::indicate_error (mp_ui->angle_le, 0);
lay::indicate_error (mp_ui->angle_le, (tl::Exception *) 0);
bool mirror = false;
root->config_get (cfg_edit_inst_mirror, mirror);
@ -640,7 +640,7 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
double scale = 1.0;
root->config_get (cfg_edit_inst_scale, scale);
mp_ui->scale_le->setText (tl::to_qstring (tl::to_string (scale)));
lay::indicate_error (mp_ui->scale_le, 0);
lay::indicate_error (mp_ui->scale_le, (tl::Exception *) 0);
// array
bool array = false;
@ -657,17 +657,17 @@ EditorOptionsInst::setup (lay::Dispatcher *root)
root->config_get (cfg_edit_inst_column_y, column_y);
mp_ui->rows_le->setText (tl::to_qstring (tl::to_string (rows)));
lay::indicate_error (mp_ui->rows_le, 0);
lay::indicate_error (mp_ui->rows_le, (tl::Exception *) 0);
mp_ui->row_x_le->setText (tl::to_qstring (tl::to_string (row_x)));
lay::indicate_error (mp_ui->row_x_le, 0);
lay::indicate_error (mp_ui->row_x_le, (tl::Exception *) 0);
mp_ui->row_y_le->setText (tl::to_qstring (tl::to_string (row_y)));
lay::indicate_error (mp_ui->row_y_le, 0);
lay::indicate_error (mp_ui->row_y_le, (tl::Exception *) 0);
mp_ui->columns_le->setText (tl::to_qstring (tl::to_string (columns)));
lay::indicate_error (mp_ui->columns_le, 0);
lay::indicate_error (mp_ui->columns_le, (tl::Exception *) 0);
mp_ui->column_x_le->setText (tl::to_qstring (tl::to_string (column_x)));
lay::indicate_error (mp_ui->column_x_le, 0);
lay::indicate_error (mp_ui->column_x_le, (tl::Exception *) 0);
mp_ui->column_y_le->setText (tl::to_qstring (tl::to_string (column_y)));
lay::indicate_error (mp_ui->column_y_le, 0);
lay::indicate_error (mp_ui->column_y_le, (tl::Exception *) 0);
// place origin of cell flag
bool place_origin = false;

View File

@ -405,7 +405,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
throw tl::Exception (tl::to_string (QObject::tr ("Not a valid cell or PCell name: %s")).c_str (), tl::to_string (cell_name_le->text ()).c_str ());
}
lay::indicate_error (cell_name_le, 0);
lay::indicate_error (cell_name_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (cell_name_le, &ex);
@ -447,7 +447,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (pos_x_le->text ()), x);
lay::indicate_error (pos_x_le, 0);
lay::indicate_error (pos_x_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (pos_x_le, &ex);
has_error = true;
@ -455,7 +455,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (pos_y_le->text ()), y);
lay::indicate_error (pos_y_le, 0);
lay::indicate_error (pos_y_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (pos_y_le, &ex);
has_error = true;
@ -472,7 +472,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
double angle = 0.0;
try {
tl::from_string (tl::to_string (angle_le->text ()), angle);
lay::indicate_error (angle_le, 0);
lay::indicate_error (angle_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (angle_le, &ex);
has_error = true;
@ -481,7 +481,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
double mag = 0.0;
try {
tl::from_string (tl::to_string (mag_le->text ()), mag);
lay::indicate_error (mag_le, 0);
lay::indicate_error (mag_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (mag_le, &ex);
has_error = true;
@ -510,7 +510,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (column_x_le->text ()), cx);
lay::indicate_error (column_x_le, 0);
lay::indicate_error (column_x_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (column_x_le, &ex);
has_error = true;
@ -518,7 +518,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (column_y_le->text ()), cy);
lay::indicate_error (column_y_le, 0);
lay::indicate_error (column_y_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (column_y_le, &ex);
has_error = true;
@ -526,7 +526,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (row_x_le->text ()), rx);
lay::indicate_error (row_x_le, 0);
lay::indicate_error (row_x_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (row_x_le, &ex);
has_error = true;
@ -534,7 +534,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (row_y_le->text ()), ry);
lay::indicate_error (row_y_le, 0);
lay::indicate_error (row_y_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (row_y_le, &ex);
has_error = true;
@ -542,7 +542,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (rows_le->text ()), rows);
lay::indicate_error (rows_le, 0);
lay::indicate_error (rows_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (rows_le, &ex);
has_error = true;
@ -550,7 +550,7 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance &
try {
tl::from_string (tl::to_string (columns_le->text ()), cols);
lay::indicate_error (columns_le, 0);
lay::indicate_error (columns_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (columns_le, &ex);
has_error = true;
@ -766,7 +766,7 @@ InstPropertiesPage::update_pcell_parameters ()
tl::Exception ex (tl::to_string (QObject::tr ("Not a valid cell or PCell name: %s")).c_str (), tl::to_string (cell_name_le->text ()).c_str ());
lay::indicate_error (cell_name_le, &ex);
} else {
lay::indicate_error (cell_name_le, 0);
lay::indicate_error (cell_name_le, (tl::Exception *) 0);
}
if (pc.first && layout->pcell_declaration (pc.second)) {

View File

@ -496,7 +496,7 @@ PCellParametersPage::get_parameters (bool *ok)
tl::from_string (tl::to_string (le->text ()), v);
parameters.back () = tl::Variant (v);
lay::indicate_error (le, 0);
lay::indicate_error (le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
@ -520,7 +520,7 @@ PCellParametersPage::get_parameters (bool *ok)
tl::from_string (tl::to_string (le->text ()), v);
parameters.back () = tl::Variant (v);
lay::indicate_error (le, 0);
lay::indicate_error (le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {

View File

@ -509,7 +509,7 @@ PolygonPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Sha
}
lay::indicate_error (pointListEdit, 0);
lay::indicate_error (pointListEdit, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (pointListEdit, &ex);
@ -609,7 +609,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (x1_le_1->text ()), x1);
lay::indicate_error (x1_le_1, 0);
lay::indicate_error (x1_le_1, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x1_le_1, &ex);
has_error = true;
@ -617,7 +617,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (y1_le_1->text ()), y1);
lay::indicate_error (y1_le_1, 0);
lay::indicate_error (y1_le_1, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y1_le_1, &ex);
has_error = true;
@ -625,7 +625,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (x2_le_1->text ()), x2);
lay::indicate_error (x2_le_1, 0);
lay::indicate_error (x2_le_1, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x2_le_1, &ex);
has_error = true;
@ -633,7 +633,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (y2_le_1->text ()), y2);
lay::indicate_error (y2_le_1, 0);
lay::indicate_error (y2_le_1, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y2_le_1, &ex);
has_error = true;
@ -669,7 +669,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (cx_le_2->text ()), cx);
lay::indicate_error (cx_le_2, 0);
lay::indicate_error (cx_le_2, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (cx_le_2, &ex);
has_error = true;
@ -677,7 +677,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (cy_le_2->text ()), cy);
lay::indicate_error (cy_le_2, 0);
lay::indicate_error (cy_le_2, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (cy_le_2, &ex);
has_error = true;
@ -685,7 +685,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (w_le_2->text ()), w);
lay::indicate_error (w_le_2, 0);
lay::indicate_error (w_le_2, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (w_le_2, &ex);
has_error = true;
@ -693,7 +693,7 @@ BoxPropertiesPage::get_box (int mode) const
try {
tl::from_string (tl::to_string (h_le_2->text ()), h);
lay::indicate_error (h_le_2, 0);
lay::indicate_error (h_le_2, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (h_le_2, &ex);
has_error = true;
@ -834,7 +834,7 @@ TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape
try {
tl::from_string (tl::to_string (x_le->text ()), x);
lay::indicate_error (x_le, 0);
lay::indicate_error (x_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x_le, &ex);
has_error = true;
@ -842,7 +842,7 @@ TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape
try {
tl::from_string (tl::to_string (y_le->text ()), y);
lay::indicate_error (y_le, 0);
lay::indicate_error (y_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y_le, &ex);
has_error = true;
@ -875,7 +875,7 @@ TextPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db::Shape
if (! size_le->text ().isEmpty ()) {
try {
size = coord_from_string (tl::to_string (size_le->text ()).c_str (), dbu, du, t);
lay::indicate_error (size_le, 0);
lay::indicate_error (size_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (size_le, &ex);
has_error = true;
@ -1084,7 +1084,7 @@ EditablePathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db
throw tl::Exception (tl::to_string (QObject::tr ("The path must have at least one point")));
}
lay::indicate_error (ptlist_le, 0);
lay::indicate_error (ptlist_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (ptlist_le, &ex);
@ -1094,7 +1094,7 @@ EditablePathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db
db::Coord w = 0;
try {
w = coord_from_string (tl::to_string (width_le->text ()).c_str (), dbu, du, t);
lay::indicate_error (width_le, 0);
lay::indicate_error (width_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (width_le, &ex);
has_error = true;
@ -1111,14 +1111,14 @@ EditablePathPropertiesPage::create_applicator (db::Shapes & /*shapes*/, const db
case 2: // variable
try {
se = coord_from_string (tl::to_string (start_ext_le->text ()).c_str (), dbu, du, t);
lay::indicate_error (start_ext_le, 0);
lay::indicate_error (start_ext_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (start_ext_le, &ex);
has_error = true;
}
try {
ee = coord_from_string (tl::to_string (end_ext_le->text ()).c_str (), dbu, du, t);
lay::indicate_error (end_ext_le, 0);
lay::indicate_error (end_ext_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (end_ext_le, &ex);
has_error = true;

View File

@ -219,7 +219,7 @@ PropertiesPage::get_xmin_xmax (double &xmin, double &xmax, bool &has_error_out)
try {
tl::from_string (tl::to_string (from_le->text ()), xmin);
lay::indicate_error (from_le, 0);
lay::indicate_error (from_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (from_le, &ex);
has_error = true;
@ -227,7 +227,7 @@ PropertiesPage::get_xmin_xmax (double &xmin, double &xmax, bool &has_error_out)
try {
tl::from_string (tl::to_string (to_le->text ()), xmax);
lay::indicate_error (to_le, 0);
lay::indicate_error (to_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (to_le, &ex);
has_error = true;
@ -336,7 +336,7 @@ PropertiesPage::value_changed ()
double x = 0.0;
try {
tl::from_string (tl::to_string (value_le->text ()), x);
lay::indicate_error (value_le, 0);
lay::indicate_error (value_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (value_le, &ex);
has_error = true;
@ -805,7 +805,7 @@ PropertiesPage::apply ()
if (w <= 0.0 || h <= 0.0) {
throw tl::Exception (tl::to_string (QObject::tr ("Pixel width or height must be positive, non-null values")));
}
lay::indicate_error (width_le, 0);
lay::indicate_error (width_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (width_le, &ex);
has_error = true;
@ -813,7 +813,7 @@ PropertiesPage::apply ()
try {
tl::from_string (tl::to_string (height_le->text ()), h);
lay::indicate_error (height_le, 0);
lay::indicate_error (height_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (height_le, &ex);
has_error = true;
@ -821,7 +821,7 @@ PropertiesPage::apply ()
try {
tl::from_string (tl::to_string (x_offset_le->text ()), x);
lay::indicate_error (x_offset_le, 0);
lay::indicate_error (x_offset_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (x_offset_le, &ex);
has_error = true;
@ -829,7 +829,7 @@ PropertiesPage::apply ()
try {
tl::from_string (tl::to_string (y_offset_le->text ()), y);
lay::indicate_error (y_offset_le, 0);
lay::indicate_error (y_offset_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (y_offset_le, &ex);
has_error = true;
@ -837,7 +837,7 @@ PropertiesPage::apply ()
try {
tl::from_string (tl::to_string (angle_le->text ()), a);
lay::indicate_error (angle_le, 0);
lay::indicate_error (angle_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (angle_le, &ex);
has_error = true;
@ -848,7 +848,7 @@ PropertiesPage::apply ()
if (sa <= -45 || sa >= 45) {
throw tl::Exception (tl::to_string (QObject::tr ("The shear angle must be larger than -45 and less than 45 degree")));
}
lay::indicate_error (shear_le, 0);
lay::indicate_error (shear_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (shear_le, &ex);
has_error = true;
@ -859,7 +859,7 @@ PropertiesPage::apply ()
if (tx <= -90 || tx >= 90) {
throw tl::Exception (tl::to_string (QObject::tr ("The perspective tilt angles must be larger than -90 and less than 90 degree")));
}
lay::indicate_error (persp_tx_le, 0);
lay::indicate_error (persp_tx_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (persp_tx_le, &ex);
has_error = true;
@ -870,7 +870,7 @@ PropertiesPage::apply ()
if (ty <= -90 || ty >= 90) {
throw tl::Exception (tl::to_string (QObject::tr ("The perspective tilt angles must be larger than -90 and less than 90 degree")));
}
lay::indicate_error (persp_ty_le, 0);
lay::indicate_error (persp_ty_le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (persp_ty_le, &ex);
has_error = true;

View File

@ -1383,63 +1383,6 @@ p, li { white-space: pre-wrap; }
</widget>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_5">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Close</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
<action name="actionNewFolder">
<property name="icon">
@ -1596,22 +1539,5 @@ p, li { white-space: pre-wrap; }
<resources>
<include location="layResources.qrc"/>
</resources>
<connections>
<connection>
<sender>pushButton</sender>
<signal>clicked()</signal>
<receiver>MacroEditorDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>905</x>
<y>694</y>
</hint>
<hint type="destinationlabel">
<x>929</x>
<y>696</y>
</hint>
</hints>
</connection>
</connections>
<connections/>
</ui>

View File

@ -355,8 +355,8 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection
QMenu *m = new QMenu (searchEditBox);
m->addAction (actionUseRegularExpressions);
m->addAction (actionCaseSensitive);
connect (actionUseRegularExpressions, SIGNAL (triggered ()), this, SLOT (apply_search ()));
connect (actionCaseSensitive, SIGNAL (triggered ()), this, SLOT (apply_search ()));
connect (actionUseRegularExpressions, SIGNAL (triggered ()), this, SLOT (search_editing ()));
connect (actionCaseSensitive, SIGNAL (triggered ()), this, SLOT (search_editing ()));
addAction (actionSearchReplace);
connect (actionSearchReplace, SIGNAL (triggered ()), this, SLOT (search_replace ()));
@ -364,7 +364,11 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection
searchEditBox->set_clear_button_enabled (true);
searchEditBox->set_options_button_enabled (true);
searchEditBox->set_options_menu (m);
searchEditBox->set_escape_signal_enabled (true);
searchEditBox->set_tab_signal_enabled (true);
replaceText->set_clear_button_enabled (true);
replaceText->set_escape_signal_enabled (true);
replaceText->set_tab_signal_enabled (true);
#if QT_VERSION >= 0x40700
searchEditBox->setPlaceholderText (tr ("Find text ..."));
replaceText->setPlaceholderText (tr ("Replace text ..."));
@ -382,8 +386,6 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection
tabWidget->setMovable (true);
tabWidget->setTabsClosable (true);
connect (tabWidget, SIGNAL (tabCloseRequested (int)), this, SLOT (tab_close_requested (int)));
closeButton->hide ();
closeButtonSeparator->hide ();
#endif
dbgOn->setEnabled (true);
@ -411,7 +413,6 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection
connect (helpButton, SIGNAL (clicked ()), this, SLOT (help_button_clicked ()));
connect (addButton, SIGNAL (clicked ()), this, SLOT (add_button_clicked ()));
connect (actionAddMacro, SIGNAL (triggered ()), this, SLOT (add_button_clicked ()));
connect (closeButton, SIGNAL (clicked ()), this, SLOT (close_button_clicked ()));
connect (deleteButton, SIGNAL (clicked ()), this, SLOT (delete_button_clicked ()));
connect (actionDelete, SIGNAL (triggered ()), this, SLOT (delete_button_clicked ()));
connect (renameButton, SIGNAL (clicked ()), this, SLOT (rename_button_clicked ()));
@ -438,9 +439,16 @@ MacroEditorDialog::MacroEditorDialog (lay::Dispatcher *pr, lym::MacroCollection
connect (callStack, SIGNAL (itemDoubleClicked (QListWidgetItem *)), this, SLOT (stack_element_double_clicked (QListWidgetItem *)));
connect (singleStepButton, SIGNAL (clicked ()), this, SLOT (single_step_button_clicked ()));
connect (nextStepButton, SIGNAL (clicked ()), this, SLOT (next_step_button_clicked ()));
connect (searchEditBox, SIGNAL (textEdited (const QString &)), this, SLOT (search_editing ()));
connect (searchEditBox, SIGNAL (returnPressed ()), this, SLOT (search_edited ()));
connect (searchEditBox, SIGNAL (editingFinished ()), this, SLOT (search_edited ()));
connect (searchEditBox, SIGNAL (textEdited (QString)), this, SLOT (apply_search ()));
connect (searchEditBox, SIGNAL (esc_pressed ()), this, SLOT (search_finished ()));
connect (searchEditBox, SIGNAL (tab_pressed ()), this, SLOT (find_next_button_clicked ()));
connect (searchEditBox, SIGNAL (backtab_pressed ()), this, SLOT (find_prev_button_clicked ()));
connect (replaceText, SIGNAL (esc_pressed ()), this, SLOT (search_finished ()));
connect (replaceText, SIGNAL (tab_pressed ()), this, SLOT (find_next_button_clicked ()));
connect (replaceText, SIGNAL (backtab_pressed ()), this, SLOT (find_prev_button_clicked ()));
connect (replaceText, SIGNAL (returnPressed ()), this, SLOT (replace_next_button_clicked ()));
connect (replaceModeButton, SIGNAL (clicked ()), this, SLOT (replace_mode_button_clicked ()));
connect (replaceNextButton, SIGNAL (clicked ()), this, SLOT (replace_next_button_clicked ()));
connect (findNextButton, SIGNAL (clicked ()), this, SLOT (find_next_button_clicked ()));
@ -946,15 +954,13 @@ MacroEditorDialog::showEvent (QShowEvent *)
void
MacroEditorDialog::reject ()
{
closeEvent (0);
QDialog::reject ();
// .. ignore Esc ..
}
void
MacroEditorDialog::accept ()
{
closeEvent (0);
QDialog::accept ();
// .. ignore Enter ..
}
void
@ -1105,12 +1111,6 @@ MacroEditorDialog::can_exit ()
return true;
}
void
MacroEditorDialog::search_replace ()
{
searchEditBox->setFocus (Qt::TabFocusReason);
}
void
MacroEditorDialog::add_edit_trace (bool compress)
{
@ -1882,6 +1882,18 @@ BEGIN_PROTECTED
END_PROTECTED
}
void
MacroEditorDialog::set_editor_focus ()
{
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
if (! page) {
return;
}
lay::SignalBlocker signal_blocker (searchEditBox);
page->set_editor_focus ();
}
void
MacroEditorDialog::replace_mode_button_clicked ()
{
@ -1905,10 +1917,27 @@ MacroEditorDialog::find_next_button_clicked ()
apply_search (true);
page->find_next ();
page->set_editor_focus ();
if (sender () != searchEditBox && sender () != replaceText) {
set_editor_focus ();
}
}
void
void
MacroEditorDialog::find_prev_button_clicked ()
{
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
if (! page) {
return;
}
apply_search (true);
page->find_prev ();
if (sender () != searchEditBox && sender () != replaceText) {
set_editor_focus ();
}
}
void
MacroEditorDialog::replace_next_button_clicked ()
{
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
@ -1918,10 +1947,12 @@ MacroEditorDialog::replace_next_button_clicked ()
apply_search (true);
page->replace_and_find_next (replaceText->text ());
page->set_editor_focus ();
if (sender () != replaceText) {
set_editor_focus ();
}
}
void
void
MacroEditorDialog::replace_all_button_clicked ()
{
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
@ -1931,7 +1962,34 @@ MacroEditorDialog::replace_all_button_clicked ()
apply_search (true);
page->replace_all (replaceText->text ());
page->set_editor_focus ();
set_editor_focus ();
}
void
MacroEditorDialog::search_requested (const QString &s)
{
searchEditBox->setText (s);
searchEditBox->setFocus ();
search_editing ();
}
void
MacroEditorDialog::search_replace ()
{
searchEditBox->setFocus (Qt::TabFocusReason);
}
void
MacroEditorDialog::search_editing ()
{
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
if (! page) {
return;
}
apply_search ();
page->find_reset (); // search from the initial position
page->find_next ();
}
void
@ -1942,6 +2000,18 @@ MacroEditorDialog::search_edited ()
md_search_edited ();
}
void
MacroEditorDialog::search_finished ()
{
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
if (! page) {
return;
}
page->find_reset (); // search from the initial position
set_editor_focus ();
}
void
MacroEditorDialog::do_search_edited ()
{
@ -1951,8 +2021,9 @@ MacroEditorDialog::do_search_edited ()
}
apply_search ();
page->find_reset (); // search from the initial position
page->find_next ();
page->set_editor_focus ();
set_editor_focus ();
}
void
@ -1963,7 +2034,7 @@ MacroEditorDialog::apply_search (bool if_needed)
return;
}
if (searchEditBox->text ().size () > 0) {
if (! searchEditBox->text ().isEmpty ()) {
QRegExp re (searchEditBox->text (),
actionCaseSensitive->isChecked () ? Qt::CaseSensitive : Qt::CaseInsensitive,
actionUseRegularExpressions->isChecked () ? QRegExp::RegExp : QRegExp::FixedString);
@ -2080,7 +2151,7 @@ BEGIN_PROTECTED
END_PROTECTED
}
void
void
MacroEditorDialog::help_requested(const QString &s)
{
lay::MainWindow::instance ()->show_assistant_topic (tl::to_string (s));
@ -3172,7 +3243,6 @@ MacroEditorDialog::do_update_ui_to_run_mode ()
addButton->setEnabled (! m_in_exec);
actionAddMacro->setEnabled (! m_in_exec);
closeButton->setEnabled (! m_in_exec);
deleteButton->setEnabled (! m_in_exec);
actionDelete->setEnabled (! m_in_exec);
renameButton->setEnabled (! m_in_exec);
@ -3270,6 +3340,7 @@ MacroEditorDialog::create_page (lym::Macro *macro)
editor->exec_model ()->set_run_mode (m_in_exec);
editor->connect_macro (macro);
connect (editor.get (), SIGNAL (help_requested (const QString &)), this, SLOT (help_requested (const QString &)));
connect (editor.get (), SIGNAL (search_requested (const QString &)), this, SLOT (search_requested (const QString &)));
connect (editor.get (), SIGNAL (edit_trace (bool)), this, SLOT (add_edit_trace (bool)));
return editor.release ();
}

View File

@ -209,12 +209,16 @@ private slots:
void commit ();
void stack_element_double_clicked (QListWidgetItem *item);
void search_edited ();
void search_editing ();
void search_finished ();
void tab_close_requested (int);
void replace_mode_button_clicked ();
void replace_next_button_clicked ();
void replace_all_button_clicked ();
void find_next_button_clicked ();
void find_prev_button_clicked ();
void help_requested (const QString &s);
void search_requested (const QString &s);
void macro_changed (lym::Macro *macro);
void macro_deleted (lym::Macro *macro);
void macro_collection_deleted (lym::MacroCollection *collection);
@ -288,6 +292,7 @@ private:
void update_watches ();
lym::Macro *new_macro ();
void do_search_edited ();
void set_editor_focus ();
void select_trace (size_t index);
bool configure (const std::string &name, const std::string &value);
void config_finalize ();

View File

@ -42,6 +42,9 @@
#include <QChar>
#include <QResource>
#include <QBuffer>
#include <QTimer>
#include <QListWidget>
#include <QApplication>
namespace lay
{
@ -475,7 +478,7 @@ void MacroEditorSidePanel::paintEvent (QPaintEvent *)
// MacroEditorPage implementation
MacroEditorPage::MacroEditorPage (QWidget * /*parent*/, MacroEditorHighlighters *highlighters)
: mp_macro (0), mp_highlighters (highlighters), mp_highlighter (0), m_error_line (-1), m_ntab (8), m_nindent (2)
: mp_macro (0), mp_highlighters (highlighters), mp_highlighter (0), m_error_line (-1), m_ntab (8), m_nindent (2), m_ignore_cursor_changed_event (false)
{
QVBoxLayout *layout = new QVBoxLayout (this);
@ -499,11 +502,26 @@ MacroEditorPage::MacroEditorPage (QWidget * /*parent*/, MacroEditorHighlighters
connect (mp_text, SIGNAL (textChanged ()), this, SLOT (text_changed ()));
connect (mp_text, SIGNAL (cursorPositionChanged ()), this, SLOT (cursor_position_changed ()));
connect (mp_text->horizontalScrollBar (), SIGNAL (valueChanged (int)), this, SLOT (hide_completer ()));
connect (mp_text->verticalScrollBar (), SIGNAL (valueChanged (int)), this, SLOT (hide_completer ()));
connect (mp_exec_model, SIGNAL (breakpoints_changed ()), this, SLOT (breakpoints_changed ()));
connect (mp_exec_model, SIGNAL (current_line_changed ()), this, SLOT (current_line_changed ()));
connect (mp_exec_model, SIGNAL (run_mode_changed ()), this, SLOT (run_mode_changed ()));
mp_text->installEventFilter (this);
mp_completer_popup = new QWidget (window (), Qt::ToolTip);
mp_completer_popup->setWindowModality (Qt::NonModal);
QHBoxLayout *ly = new QHBoxLayout (mp_completer_popup);
ly->setMargin (0);
mp_completer_list = new QListWidget (mp_completer_popup);
ly->addWidget (mp_completer_list);
mp_completer_popup->hide ();
mp_completer_timer = new QTimer (this);
mp_completer_timer->setInterval (1000);
mp_completer_timer->setSingleShot (true);
connect (mp_completer_timer, SIGNAL (timeout ()), this, SLOT (completer_timer ()));
}
void MacroEditorPage::update ()
@ -598,9 +616,110 @@ static bool valid_element (const SyntaxHighlighterElement &e)
return e.basic_attribute_id != lay::dsComment && e.basic_attribute_id != lay::dsString;
}
void MacroEditorPage::complete ()
{
QTextCursor c = mp_text->textCursor ();
if (c.selectionStart () != c.selectionEnd ()) {
return;
}
c.select (QTextCursor::WordUnderCursor);
if (mp_completer_list->currentItem ()) {
QString s = mp_completer_list->currentItem ()->text ();
c.insertText (s);
}
}
void MacroEditorPage::fill_completer_list ()
{
QTextCursor c = mp_text->textCursor ();
if (c.selectionStart () != c.selectionEnd ()) {
return;
}
int pos = c.anchor ();
c.select (QTextCursor::WordUnderCursor);
int pos0 = c.selectionStart ();
if (pos0 >= pos) {
return;
}
QString ssel = c.selectedText ();
QString s = ssel.mid (0, pos - pos0);
QString text = mp_text->toPlainText ();
std::set<QString> words;
int i = 0;
while (i >= 0) {
i = text.indexOf (s, i);
if (i >= 0) {
QString::iterator c = text.begin () + i;
QString w;
while (c->isLetterOrNumber () || c->toLatin1 () == '_') {
w += *c;
++c;
}
if (! w.isEmpty () && w != s && w != ssel) {
words.insert (w);
}
++i;
}
}
for (std::set<QString>::const_iterator w = words.begin (); w != words.end (); ++w) {
mp_completer_list->addItem (*w);
}
}
void MacroEditorPage::completer_timer ()
{
if (! mp_text->hasFocus ()) {
return;
}
mp_completer_list->clear ();
fill_completer_list ();
if (mp_completer_list->count () > 0) {
mp_completer_list->setCurrentRow (0);
QTextCursor c = mp_text->textCursor ();
c.clearSelection ();
QRect r = mp_text->cursorRect (c);
QPoint pos = mp_text->mapToGlobal (r.bottomLeft ());
QSize sz = mp_completer_list->sizeHint ();
QFontMetrics fm (mp_completer_list->font ());
mp_completer_popup->setGeometry (pos.x (), pos.y () + r.height () / 3, sz.width (), 4 + 4 * fm.height () /*sz.height ()*/);
mp_completer_popup->show ();
mp_text->setFocus ();
} else {
mp_completer_popup->hide ();
}
}
void MacroEditorPage::hide_completer ()
{
mp_completer_popup->hide ();
}
void MacroEditorPage::cursor_position_changed ()
{
if (m_ignore_cursor_changed_event) {
return;
}
mp_completer_popup->hide ();
mp_completer_timer->stop ();
mp_completer_timer->start ();
QTextCursor cursor = mp_text->textCursor ();
m_edit_cursor = cursor;
// prepare a format for the bracket highlights
QTextCharFormat fmt;
@ -861,11 +980,23 @@ void MacroEditorPage::connect_macro (lym::Macro *macro)
}
}
void
MacroEditorPage::find_reset ()
{
m_ignore_cursor_changed_event = true;
mp_text->setTextCursor (m_edit_cursor);
m_ignore_cursor_changed_event = false;
}
bool
MacroEditorPage::find_prev ()
{
update_extra_selections ();
if (m_current_search == QRegExp ()) {
return false;
}
QTextCursor c = mp_text->textCursor ();
bool first = true;
@ -891,7 +1022,9 @@ MacroEditorPage::find_prev ()
QTextCursor newc (b);
newc.setPosition (i + b.position () + l);
newc.setPosition (i + b.position (), QTextCursor::KeepAnchor);
m_ignore_cursor_changed_event = true;
mp_text->setTextCursor (newc);
m_ignore_cursor_changed_event = false;
return true;
}
@ -913,6 +1046,10 @@ MacroEditorPage::find_next ()
{
update_extra_selections ();
if (m_current_search == QRegExp ()) {
return false;
}
QTextCursor c = mp_text->textCursor ();
bool first = true;
@ -926,7 +1063,9 @@ MacroEditorPage::find_next ()
QTextCursor newc (b);
newc.setPosition (i + b.position () + m_current_search.matchedLength ());
newc.setPosition (i + b.position (), QTextCursor::KeepAnchor);
m_ignore_cursor_changed_event = true;
mp_text->setTextCursor (newc);
m_ignore_cursor_changed_event = false;
emit edit_trace (false);
return true;
}
@ -1152,263 +1291,319 @@ MacroEditorPage::current_pos () const
return mp_text->textCursor ().position () - mp_text->textCursor ().block ().position ();
}
bool
MacroEditorPage::tab_key_pressed ()
{
if (mp_text->isReadOnly ()) {
return false;
}
QTextBlock bs, be;
bool adjust_end = false;
bool indent = false;
if (mp_text->textCursor ().hasSelection ()) {
bs = mp_text->document ()->findBlock (mp_text->textCursor ().selectionStart ());
be = mp_text->document ()->findBlock (mp_text->textCursor ().selectionEnd ());
if (be != bs) {
indent = true;
QTextCursor se (mp_text->document ());
se.setPosition (mp_text->textCursor ().selectionEnd ());
if (se.atBlockStart ()) {
be = be.previous ();
adjust_end = true;
}
}
}
if (indent) {
// tab out
QTextCursor c (mp_text->document ());
c.setPosition (bs.position ());
c.beginEditBlock ();
for (QTextBlock b = bs; ; b = b.next()) {
c.setPosition (b.position ());
QString text = b.text ();
bool has_tabs = false;
int p = 0;
int i = 0;
for (; i < text.length (); ++i) {
if (text [i] == QChar::fromLatin1 (' ')) {
++p;
} else if (text [i] == QChar::fromLatin1 ('\t')) {
p = (p - p % m_ntab) + m_ntab;
has_tabs = true;
} else {
break;
}
}
if (has_tabs) {
for ( ; i > 0; --i) {
c.deleteChar ();
}
c.insertText (QString (m_nindent + p, QChar::fromLatin1 (' ')));
} else {
c.insertText (QString (m_nindent, QChar::fromLatin1 (' ')));
}
if (b == be) {
break;
}
}
c.endEditBlock ();
c.setPosition (bs.position ());
if (adjust_end) {
c.setPosition (be.next ().position (), QTextCursor::KeepAnchor);
} else {
c.setPosition (be.position () + be.text ().length (), QTextCursor::KeepAnchor);
}
mp_text->setTextCursor (c);
} else {
QTextCursor c = mp_text->textCursor ();
QString text = c.block ().text ();
int col = c.position () - c.block ().position ();
int p = 0;
for (int i = 0; i < text.length () && i < col; ++i) {
if (text [i] == QChar::fromLatin1 ('\t')) {
p = (p - p % m_ntab) + m_ntab;
} else {
++p;
}
}
c.insertText (QString (m_nindent - p % m_nindent, QChar::fromLatin1 (' ')));
mp_text->setTextCursor (c);
}
return true;
}
bool
MacroEditorPage::back_tab_key_pressed ()
{
if (!mp_text->textCursor ().hasSelection () || mp_text->isReadOnly ()) {
return false;
}
// tab in
QTextBlock bs = mp_text->document ()->findBlock (mp_text->textCursor ().selectionStart ());
QTextBlock be = mp_text->document ()->findBlock (mp_text->textCursor ().selectionEnd ());
bool adjust_end = false;
if (be != bs) {
QTextCursor se (mp_text->document ());
se.setPosition (mp_text->textCursor ().selectionEnd ());
if (se.atBlockStart ()) {
be = be.previous ();
adjust_end = true;
}
}
QTextCursor c (mp_text->document ());
c.setPosition (bs.position ());
c.beginEditBlock ();
for (QTextBlock b = bs; ; b = b.next()) {
c.setPosition (b.position ());
QString text = b.text ();
int n = m_nindent;
int p = 0;
for (int i = 0; i < text.length () && n > 0; ++i) {
if (text [i] == QChar::fromLatin1 (' ')) {
++p;
--n;
c.deleteChar ();
} else if (text [i] == QChar::fromLatin1 ('\t')) {
c.deleteChar ();
int pp = p;
p = (p - p % m_ntab) + m_ntab;
if (p - pp >= n) {
if (p - pp > n) {
c.insertText (QString (p - pp - n, QChar::fromLatin1 (' ')));
}
n = 0;
} else {
n -= p - pp;
}
} else {
break;
}
}
if (b == be) {
break;
}
}
c.endEditBlock ();
c.setPosition (bs.position ());
if (adjust_end) {
c.setPosition (be.next ().position (), QTextCursor::KeepAnchor);
} else {
c.setPosition (be.position () + be.text ().length (), QTextCursor::KeepAnchor);
}
mp_text->setTextCursor (c);
return true;
}
bool
MacroEditorPage::backspace_pressed ()
{
if (mp_text->textCursor ().hasSelection () || mp_text->isReadOnly()) {
return false;
}
QTextCursor c = mp_text->textCursor ();
QString text = c.block ().text ();
int col = c.position () - c.block ().position ();
if (col > 0) {
int p = 0;
bool only_space_before = true;
for (int i = 0; i < text.length () && i < col; ++i) {
if (text [i] == QChar::fromLatin1 ('\t')) {
p = (p - p % m_ntab) + m_ntab;
} else if (text [i] == QChar::fromLatin1 (' ')) {
++p;
} else {
only_space_before = false;
}
}
if (only_space_before) {
for (int i = 0; i < col; ++i) {
c.deletePreviousChar ();
}
c.insertText (QString (std::max (0, ((p - 1) / m_nindent) * m_nindent), QChar::fromLatin1 (' ')));
mp_text->setTextCursor (c);
return true;
}
}
return false;
}
bool
MacroEditorPage::return_pressed ()
{
if (mp_text->isReadOnly ()) {
return false;
}
// Implement auto-indent on return
QTextCursor c = mp_text->textCursor ();
QTextBlock b = c.block ();
c.insertBlock ();
QString l;
if (b.isValid ()) {
QString text = b.text ();
for (int i = 0; i < text.length (); ++i) {
if (text [i] == QChar::fromLatin1 ('\t') || text [i] == QChar::fromLatin1 (' ')) {
l += text [i];
} else {
break;
}
}
}
c.insertText (l);
mp_text->setTextCursor (c);
return true;
}
bool
MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
{
if (watched == mp_text) {
if (event->type () == QEvent::KeyPress) {
if (event->type () == QEvent::ShortcutOverride) {
// override shortcuts
event->accept ();
return true;
} else if (event->type () == QEvent::FocusOut) {
hide_completer ();
return true;
} else if (event->type () == QEvent::KeyPress) {
m_error_line = -1;
mp_text->setExtraSelections (QList<QTextEdit::ExtraSelection> ());
QKeyEvent *ke = dynamic_cast<QKeyEvent *> (event);
if (ke && ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) == 0) {
if (! ke) {
return false; // should not happen
}
if (!mp_text->isReadOnly ()) {
QTextBlock bs, be;
bool adjust_end = false;
bool indent = false;
if (mp_text->textCursor ().hasSelection ()) {
bs = mp_text->document ()->findBlock (mp_text->textCursor ().selectionStart ());
be = mp_text->document ()->findBlock (mp_text->textCursor ().selectionEnd ());
if (be != bs) {
indent = true;
QTextCursor se (mp_text->document ());
se.setPosition (mp_text->textCursor ().selectionEnd ());
if (se.atBlockStart ()) {
be = be.previous ();
adjust_end = true;
}
}
}
if (indent) {
// tab out
QTextCursor c (mp_text->document ());
c.setPosition (bs.position ());
c.beginEditBlock ();
for (QTextBlock b = bs; ; b = b.next()) {
c.setPosition (b.position ());
QString text = b.text ();
bool has_tabs = false;
int p = 0;
int i = 0;
for (; i < text.length (); ++i) {
if (text [i] == QChar::fromLatin1 (' ')) {
++p;
} else if (text [i] == QChar::fromLatin1 ('\t')) {
p = (p - p % m_ntab) + m_ntab;
has_tabs = true;
} else {
break;
}
}
if (has_tabs) {
for ( ; i > 0; --i) {
c.deleteChar ();
}
c.insertText (QString (m_nindent + p, QChar::fromLatin1 (' ')));
} else {
c.insertText (QString (m_nindent, QChar::fromLatin1 (' ')));
}
if (b == be) {
break;
}
}
c.endEditBlock ();
c.setPosition (bs.position ());
if (adjust_end) {
c.setPosition (be.next ().position (), QTextCursor::KeepAnchor);
} else {
c.setPosition (be.position () + be.text ().length (), QTextCursor::KeepAnchor);
}
mp_text->setTextCursor (c);
} else {
QTextCursor c = mp_text->textCursor ();
QString text = c.block ().text ();
int col = c.position () - c.block ().position ();
int p = 0;
for (int i = 0; i < text.length () && i < col; ++i) {
if (text [i] == QChar::fromLatin1 ('\t')) {
p = (p - p % m_ntab) + m_ntab;
} else {
++p;
}
}
c.insertText (QString (m_nindent - p % m_nindent, QChar::fromLatin1 (' ')));
mp_text->setTextCursor (c);
}
}
return true;
} else if (ke && (ke->key () == Qt::Key_Backtab || (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) != 0))) {
if (mp_text->textCursor ().hasSelection () && !mp_text->isReadOnly ()) {
// tab in
QTextBlock bs = mp_text->document ()->findBlock (mp_text->textCursor ().selectionStart ());
QTextBlock be = mp_text->document ()->findBlock (mp_text->textCursor ().selectionEnd ());
bool adjust_end = false;
if (be != bs) {
QTextCursor se (mp_text->document ());
se.setPosition (mp_text->textCursor ().selectionEnd ());
if (se.atBlockStart ()) {
be = be.previous ();
adjust_end = true;
}
}
QTextCursor c (mp_text->document ());
c.setPosition (bs.position ());
c.beginEditBlock ();
for (QTextBlock b = bs; ; b = b.next()) {
c.setPosition (b.position ());
QString text = b.text ();
int n = m_nindent;
int p = 0;
for (int i = 0; i < text.length () && n > 0; ++i) {
if (text [i] == QChar::fromLatin1 (' ')) {
++p;
--n;
c.deleteChar ();
} else if (text [i] == QChar::fromLatin1 ('\t')) {
c.deleteChar ();
int pp = p;
p = (p - p % m_ntab) + m_ntab;
if (p - pp >= n) {
if (p - pp > n) {
c.insertText (QString (p - pp - n, QChar::fromLatin1 (' ')));
}
n = 0;
} else {
n -= p - pp;
}
} else {
break;
}
}
if (b == be) {
break;
}
}
c.endEditBlock ();
c.setPosition (bs.position ());
if (adjust_end) {
c.setPosition (be.next ().position (), QTextCursor::KeepAnchor);
} else {
c.setPosition (be.position () + be.text ().length (), QTextCursor::KeepAnchor);
}
mp_text->setTextCursor (c);
}
return true;
} else if (ke && ke->key () == Qt::Key_Backspace) {
if (!mp_text->textCursor ().hasSelection () && !mp_text->isReadOnly()) {
QTextCursor c = mp_text->textCursor ();
QString text = c.block ().text ();
int col = c.position () - c.block ().position ();
if (col > 0) {
int p = 0;
bool only_space_before = true;
for (int i = 0; i < text.length () && i < col; ++i) {
if (text [i] == QChar::fromLatin1 ('\t')) {
p = (p - p % m_ntab) + m_ntab;
} else if (text [i] == QChar::fromLatin1 (' ')) {
++p;
} else {
only_space_before = false;
}
}
if (only_space_before) {
for (int i = 0; i < col; ++i) {
c.deletePreviousChar ();
}
c.insertText (QString (std::max (0, ((p - 1) / m_nindent) * m_nindent), QChar::fromLatin1 (' ')));
mp_text->setTextCursor (c);
return true;
}
}
}
} else if (ke && ke->key () == Qt::Key_Escape) {
// Handle Esc to clear the selection
QTextCursor c = mp_text->textCursor ();
c.clearSelection ();
mp_text->setTextCursor (c);
return true;
} else if (ke && ke->key () == Qt::Key_Return) {
if (!mp_text->isReadOnly ()) {
// Implement auto-indent on return
QTextCursor c = mp_text->textCursor ();
QTextBlock b = c.block ();
c.insertBlock ();
QString l;
if (b.isValid ()) {
QString text = b.text ();
for (int i = 0; i < text.length (); ++i) {
if (text [i] == QChar::fromLatin1 ('\t') || text [i] == QChar::fromLatin1 (' ')) {
l += text [i];
} else {
break;
}
}
}
c.insertText (l);
mp_text->setTextCursor (c);
if (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) == 0) {
if (mp_completer_popup->isVisible ()) {
complete ();
return true;
} else {
return tab_key_pressed ();
}
} else if (ke && ke->key () == Qt::Key_F1) {
} else if ((ke->key () == Qt::Key_Backtab || (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) != 0))) {
return back_tab_key_pressed ();
} else if (ke->key () == Qt::Key_Backspace) {
return backspace_pressed ();
} else if (ke->key () == Qt::Key_Escape) {
// Handle Esc to return to the before-find position and clear the selection or to hide popup
if (mp_completer_popup->isVisible ()) {
mp_completer_popup->hide ();
} else {
find_reset ();
QTextCursor c = mp_text->textCursor ();
c.clearSelection ();
mp_text->setTextCursor (c);
}
return true;
} else if (ke->key () == Qt::Key_Return) {
if (mp_completer_popup->isVisible ()) {
complete ();
return true;
} else {
return return_pressed ();
}
} else if (ke->key () == Qt::Key_F1) {
QTextCursor c = mp_text->textCursor ();
if (c.selectionStart () == c.selectionEnd ()) {
@ -1418,7 +1613,19 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
return true;
} else if (ke && ke->key () == Qt::Key_F3) {
} else if (mp_completer_popup->isVisible () && (ke->key () == Qt::Key_Up || ke->key () == Qt::Key_Down)) {
QApplication::sendEvent (mp_completer_list, event);
return true;
} else if (ke->key () == Qt::Key_F && (ke->modifiers () & Qt::ControlModifier) != 0) {
QTextCursor c = mp_text->textCursor ();
emit search_requested (c.selectedText ());
return true;
} else if (ke->key () == Qt::Key_F3) {
// Jump to the next occurence of the search string

View File

@ -45,6 +45,9 @@ typedef QTextEdit TextEditWidget;
class QLabel;
class QSyntaxHighlighter;
class QTimer;
class QWindow;
class QListWidget;
namespace lay
{
@ -254,8 +257,8 @@ public:
return m_current_search;
}
void find_reset ();
bool find_next ();
bool find_prev ();
void replace_and_find_next (const QString &replace);
@ -268,6 +271,7 @@ public:
signals:
void help_requested (const QString &s);
void search_requested (const QString &s);
void edit_trace (bool);
public slots:
@ -280,6 +284,8 @@ protected slots:
void breakpoints_changed ();
void current_line_changed ();
void run_mode_changed ();
void completer_timer ();
void hide_completer ();
private:
lym::Macro *mp_macro;
@ -294,8 +300,20 @@ private:
int m_ntab, m_nindent;
std::set<QTextBlock> m_breakpoints;
QRegExp m_current_search;
QTextCursor m_edit_cursor;
bool m_ignore_cursor_changed_event;
QTimer *mp_completer_timer;
QWidget *mp_completer_popup;
QListWidget *mp_completer_list;
void update_extra_selections ();
bool return_pressed ();
bool backspace_pressed ();
bool back_tab_key_pressed ();
bool tab_key_pressed ();
void fill_completer_list ();
void complete ();
bool eventFilter (QObject *watched, QEvent *event);
};

View File

@ -87,7 +87,9 @@ struct cmp_cell_tree_item_vs_name_f
// CellTreeItem implementation
CellTreeItem::CellTreeItem (const db::Layout *layout, bool is_pcell, size_t cell_or_pcell_index, bool flat, CellTreeModel::Sorting s)
: mp_layout (layout), mp_parent (0), m_sorting (s), m_is_pcell (is_pcell), m_index (0), m_children (), m_cell_or_pcell_index (cell_or_pcell_index)
: mp_layout (layout), mp_parent (0), m_sorting (s), m_is_pcell (is_pcell),
m_index (0), m_tree_index (0),
m_children (), m_cell_or_pcell_index (cell_or_pcell_index)
{
if (! flat && ! is_pcell) {
m_child_count = int (mp_layout->cell (cell_or_pcell_index).child_cells ());
@ -104,6 +106,16 @@ CellTreeItem::~CellTreeItem ()
m_children.clear ();
}
size_t
CellTreeItem::assign_serial (size_t index, std::map<CellTreeItem *, size_t> &serial)
{
serial.insert (std::make_pair (this, index++));
for (std::vector<CellTreeItem *>::iterator c = m_children.begin (); c != m_children.end (); ++c) {
index = (*c)->assign_serial (index, serial);
}
return index;
}
bool
CellTreeItem::is_valid () const
{
@ -128,10 +140,22 @@ CellTreeItem::children () const
return m_child_count;
}
CellTreeItem *
CellTreeItem::child (int index)
int
CellTreeItem::children_in (const std::set<const CellTreeItem *> &sel) const
{
if (! m_is_pcell && int (m_children.size ()) <= index) {
size_t count = 0;
for (std::vector<CellTreeItem *>::const_iterator c = m_children.begin (); c != m_children.end (); ++c) {
if (sel.find (*c) != sel.end ()) {
++count;
}
}
return count;
}
void
CellTreeItem::ensure_children ()
{
if (! m_is_pcell && m_children.empty ()) {
// create a list of child sub-item
@ -146,10 +170,29 @@ CellTreeItem::child (int index)
finish_children ();
}
}
CellTreeItem *
CellTreeItem::child (int index)
{
ensure_children ();
return m_children [index];
}
CellTreeItem *
CellTreeItem::child_in (const std::set<const CellTreeItem *> &sel, int index)
{
ensure_children ();
for (std::vector<CellTreeItem *>::const_iterator c = m_children.begin (); c != m_children.end (); ++c) {
if (sel.find (*c) != sel.end () && index-- <= 0) {
return *c;
}
}
return 0;
}
void
CellTreeItem::add_child (CellTreeItem *item)
{
@ -274,6 +317,8 @@ CellTreeModel::CellTreeModel (QWidget *parent, lay::LayoutView *view, int cv_ind
m_flat = ((flags & Flat) != 0) && ((flags & TopCells) == 0);
m_pad = ((flags & NoPadding) == 0);
m_filter_mode = false;
m_is_filtered = false;
mp_layout = & view->cellview (cv_index)->layout ();
mp_library = 0;
@ -295,6 +340,7 @@ CellTreeModel::CellTreeModel (QWidget *parent, db::Layout *layout, unsigned int
{
m_flat = ((flags & Flat) != 0) && ((flags & TopCells) == 0);
m_pad = ((flags & NoPadding) == 0);
m_filter_mode = false;
mp_layout = layout;
mp_library = 0;
@ -316,6 +362,7 @@ CellTreeModel::CellTreeModel (QWidget *parent, db::Library *library, unsigned in
{
m_flat = ((flags & Flat) != 0) && ((flags & TopCells) == 0);
m_pad = ((flags & NoPadding) == 0);
m_filter_mode = false;
mp_layout = &library->layout ();
mp_library = library;
@ -404,6 +451,8 @@ CellTreeModel::do_configure (db::Layout *layout, db::Library *library, lay::Layo
} else {
emit layoutAboutToBeChanged ();
// Translate persistent indexes: translation happens according to the path given by
// a sequence of cell indexes.
@ -465,9 +514,9 @@ CellTreeModel::do_configure (db::Layout *layout, db::Library *library, lay::Layo
changePersistentIndexList (indexes, new_indexes);
}
emit layoutChanged ();
signal_data_changed ();
}
// TODO: harden against exceptions
for (std::vector<lay::CellTreeItem *>::iterator t = old_toplevel_items.begin (); t != old_toplevel_items.end (); ++t) {
@ -475,6 +524,15 @@ CellTreeModel::do_configure (db::Layout *layout, db::Library *library, lay::Layo
}
}
void
CellTreeModel::set_filter_mode (bool f)
{
if (f != m_filter_mode) {
m_filter_mode = f;
signal_data_changed ();
}
}
void
CellTreeModel::set_sorting (Sorting s)
{
@ -486,6 +544,7 @@ CellTreeModel::set_sorting (Sorting s)
void
CellTreeModel::signal_data_changed ()
{
emit layoutAboutToBeChanged ();
emit layoutChanged ();
}
@ -754,7 +813,7 @@ CellTreeModel::data (const QModelIndex &index, int role) const
} else if (role == Qt::BackgroundRole) {
if (m_selected_indexes_set.find (index) != m_selected_indexes_set.end ()) {
if (m_selected_indexes_set.find (index.internalPointer ()) != m_selected_indexes_set.end ()) {
// for selected items pick a color between Highlight and Base
QPalette pl (mp_parent->palette ());
QColor c1 = pl.color (QPalette::Highlight);
@ -819,11 +878,23 @@ CellTreeModel::rowCount (const QModelIndex &parent) const
} else if (! item->is_valid ()) {
// for safety we return 0 children for invalid cells
return 0;
} else if (m_filter_mode && m_is_filtered) {
return int (item->children_in (m_visible_cell_set));
} else {
return int (item->children ());
}
} else {
return int (m_toplevel.size ());
if (m_filter_mode && m_is_filtered) {
size_t n = 0;
for (std::vector <CellTreeItem *>::const_iterator i = m_toplevel.begin (); i != m_toplevel.end (); ++i) {
if (m_visible_cell_set.find (*i) != m_visible_cell_set.end ()) {
++n;
}
}
return n;
} else {
return int (m_toplevel.size ());
}
}
}
@ -839,11 +910,25 @@ CellTreeModel::index (int row, int column, const QModelIndex &parent) const
} else if (! item->is_valid ()) {
// for safety we don't return valid child indexes for invalid cells
return QModelIndex ();
} else if (m_filter_mode && m_is_filtered) {
return createIndex (row, column, item->child_in (m_visible_cell_set, row));
} else {
return createIndex (row, column, item->child (row));
}
} else if (row >= 0 && row < int (m_toplevel.size ())) {
return createIndex (row, column, m_toplevel [row]);
if (m_filter_mode && m_is_filtered) {
int n = row;
for (std::vector <CellTreeItem *>::const_iterator i = m_toplevel.begin (); i != m_toplevel.end (); ++i) {
if (m_visible_cell_set.find (*i) != m_visible_cell_set.end ()) {
if (n-- == 0) {
return createIndex (row, column, *i);
}
}
}
return QModelIndex ();
} else {
return createIndex (row, column, m_toplevel [row]);
}
} else {
return QModelIndex ();
}
@ -862,9 +947,19 @@ CellTreeModel::parent (const QModelIndex &index) const
if (! item) {
return QModelIndex ();
}
CellTreeItem *pitem = item->parent ();
if (pitem) {
return createIndex (int (pitem->index ()), index.column (), pitem);
if (m_filter_mode && m_is_filtered) {
if (pitem->tree_index () == std::numeric_limits<size_t>::max ()) {
// WARNING: invisible item!
return QModelIndex ();
} else {
return createIndex (int (pitem->tree_index ()), index.column (), pitem);
}
} else {
return createIndex (int (pitem->index ()), index.column (), pitem);
}
} else {
return QModelIndex ();
}
@ -895,6 +990,13 @@ CellTreeModel::model_index (CellTreeItem *item) const
{
if (mp_layout->under_construction () || (mp_layout->manager () && mp_layout->manager ()->transacting ())) {
return QModelIndex ();
} else if (m_filter_mode && m_is_filtered) {
if (item->tree_index () == std::numeric_limits<size_t>::max ()) {
// WARNING: invisible item!
return QModelIndex ();
} else {
return createIndex (int (item->tree_index ()), 0, item);
}
} else {
return createIndex (int (item->index ()), 0, item);
}
@ -963,10 +1065,72 @@ void
CellTreeModel::clear_locate ()
{
m_selected_indexes.clear ();
m_visible_cell_set.clear ();
m_is_filtered = false;
m_current_index = m_selected_indexes.begin ();
m_selected_indexes_set.clear ();
signal_data_changed ();
emit layoutAboutToBeChanged ();
if (m_filter_mode) {
QModelIndexList indexes = persistentIndexList ();
QModelIndexList new_indexes;
for (QModelIndexList::iterator i = indexes.begin (); i != indexes.end (); ++i) {
new_indexes.push_back (model_index ((CellTreeItem *) i->internalPointer ()));
}
changePersistentIndexList (indexes, new_indexes);
}
emit layoutChanged ();
}
QModelIndex
CellTreeModel::locate_next (const QModelIndex &index)
{
if (m_current_index == m_selected_indexes.end ()) {
return QModelIndex ();
} else if (! index.isValid ()) {
return locate_next ();
}
// easy case: the requested index is a selected one
for (std::vector <QModelIndex>::const_iterator i = m_selected_indexes.begin (); i != m_selected_indexes.end (); ++i) {
if (i->internalPointer () == index.internalPointer ()) {
m_current_index = i;
if (++m_current_index == m_selected_indexes.end ()) {
m_current_index = m_selected_indexes.begin ();
}
return *m_current_index;
}
}
// otherwise: search by sequential order
m_current_index = m_selected_indexes.begin ();
std::map<CellTreeItem *, size_t> serial_index;
size_t seq = 0;
for (size_t i = 0; i < m_toplevel.size (); ++i) {
seq = m_toplevel [i]->assign_serial (seq, serial_index);
}
size_t serial = serial_index [(CellTreeItem *) index.internalPointer ()];
size_t next = 0;
for (std::vector <QModelIndex>::const_iterator i = m_selected_indexes.begin (); i != m_selected_indexes.end (); ++i) {
size_t s = serial_index [(CellTreeItem *) i->internalPointer ()];
if (s > serial && (next == 0 || s < next)) {
next = s;
m_current_index = i;
}
}
return *m_current_index;
}
QModelIndex
@ -1005,19 +1169,42 @@ CellTreeModel::locate_prev ()
}
}
void
bool
CellTreeModel::search_children (const tl::GlobPattern &pattern, CellTreeItem *item)
{
bool any = false;
size_t ti = 0;
int children = item->children ();
for (int i = 0; i < children; ++i) {
CellTreeItem *c = item->child (i);
if (c) {
bool visible = false;
c->set_tree_index (std::numeric_limits<size_t>::max ());
if (c->name_matches (pattern)) {
c->set_tree_index (ti);
m_selected_indexes.push_back (model_index (c));
visible = true;
}
search_children (pattern, c);
if (search_children (pattern, c)) {
c->set_tree_index (ti);
visible = true;
}
if (visible) {
++ti;
m_visible_cell_set.insert (c);
any = true;
}
}
}
return any;
}
QModelIndex
@ -1027,26 +1214,75 @@ CellTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive,
return QModelIndex ();
}
emit layoutAboutToBeChanged ();
QModelIndexList indexes = persistentIndexList ();
std::vector<CellTreeItem *> persistent_index_cells;
persistent_index_cells.reserve (indexes.size ());
for (QModelIndexList::iterator i = indexes.begin (); i != indexes.end (); ++i) {
persistent_index_cells.push_back ((CellTreeItem *) i->internalPointer ());
}
m_selected_indexes.clear ();
m_visible_cell_set.clear ();
m_is_filtered = true;
tl::GlobPattern p = tl::GlobPattern (std::string (name));
p.set_case_sensitive (case_sensitive);
p.set_exact (!glob_pattern);
p.set_header_match (true);
size_t ti = 0;
for (std::vector <CellTreeItem *>::const_iterator lc = m_toplevel.begin (); lc != m_toplevel.end (); ++lc) {
bool visible = false;
(*lc)->set_tree_index (std::numeric_limits<size_t>::max ());
if ((*lc)->name_matches (p)) {
(*lc)->set_tree_index (ti);
m_selected_indexes.push_back (model_index (*lc));
visible = true;
}
if (! top_only) {
search_children (p, *lc);
if (! top_only && ! m_flat && search_children (p, *lc)) {
(*lc)->set_tree_index (ti);
visible = true;
}
if (visible) {
++ti;
m_visible_cell_set.insert (*lc);
}
}
m_selected_indexes_set.clear ();
m_selected_indexes_set.insert (m_selected_indexes.begin (), m_selected_indexes.end ());
signal_data_changed ();
for (std::vector <QModelIndex>::const_iterator i = m_selected_indexes.begin (); i != m_selected_indexes.end (); ++i) {
m_selected_indexes_set.insert (i->internalPointer ());
}
// re-layout the items
if (m_filter_mode) {
QModelIndexList new_indexes;
for (std::vector<CellTreeItem *>::const_iterator item = persistent_index_cells.begin (); item != persistent_index_cells.end (); ++item) {
if (m_visible_cell_set.find (*item) != m_visible_cell_set.end ()) {
new_indexes.push_back (model_index (*item));
} else {
new_indexes.push_back (QModelIndex ());
}
}
changePersistentIndexList (indexes, new_indexes);
}
emit layoutChanged ();
// make the first selected one current
m_current_index = m_selected_indexes.begin ();
if (m_current_index == m_selected_indexes.end ()) {

View File

@ -202,6 +202,11 @@ public:
*/
QModelIndex locate_prev ();
/**
* @brief Resets the search pointer to the one next to the given index
*/
QModelIndex locate_next (const QModelIndex &index);
/**
* @brief Clears the locate flags
*/
@ -220,12 +225,21 @@ public:
return m_sorting;
}
/**
* @brief Sets a flag indicating whether selected indexes are filtered or highlighted
*/
void set_filter_mode (bool f);
/**
* @brief Gets a flag indicating whether selected indexes are filtered or highlighted
*/
bool get_filter_mode () const
{
return m_filter_mode;
}
/**
* @brief Signal to the owner of the model that the data has changed
*
* Basically, this signal should be emitted by the model, if it knew that
* something changed. However, in our current architecture, it does not. So we
* need to tell the model that something has changed.
*/
void signal_data_changed ();
@ -239,6 +253,7 @@ public:
private:
bool m_flat, m_pad;
bool m_filter_mode, m_is_filtered;
unsigned int m_flags;
Sorting m_sorting;
QWidget *mp_parent;
@ -248,13 +263,14 @@ private:
int m_cv_index;
const db::Cell *mp_base;
std::vector <CellTreeItem *> m_toplevel;
std::set <QModelIndex> m_selected_indexes_set;
std::set <void *> m_selected_indexes_set;
std::set<const CellTreeItem *> m_visible_cell_set;
std::vector <QModelIndex> m_selected_indexes;
std::vector <QModelIndex>::const_iterator m_current_index;
void build_top_level ();
void clear_top_level ();
void search_children (const tl::GlobPattern &pattern, CellTreeItem *item);
bool search_children (const tl::GlobPattern &pattern, CellTreeItem *item);
void do_configure (db::Layout *layout, db::Library *library, lay::LayoutView *view, int cv_index, unsigned int flags, const db::Cell *base, Sorting sorting);
};
@ -271,7 +287,9 @@ public:
~CellTreeItem ();
int children () const;
int children_in (const std::set<const CellTreeItem *> &sel) const;
CellTreeItem *child (int index);
CellTreeItem *child_in (const std::set<const CellTreeItem *> &sel, int index);
db::cell_index_type cell_or_pcell_index () const;
CellTreeItem *parent () const;
bool by_name_less_than (const CellTreeItem *b) const;
@ -300,17 +318,30 @@ public:
m_index = index;
}
size_t tree_index () const
{
return m_tree_index;
}
void set_tree_index (size_t index)
{
m_tree_index = index;
}
size_t assign_serial (size_t index, std::map<CellTreeItem *, size_t> &serial);
private:
const db::Layout *mp_layout;
CellTreeItem *mp_parent;
CellTreeModel::Sorting m_sorting;
bool m_is_pcell;
size_t m_index;
size_t m_index, m_tree_index;
std::vector<CellTreeItem *> m_children;
int m_child_count;
size_t m_cell_or_pcell_index;
const char *name () const;
void ensure_children ();
};
}

View File

@ -205,7 +205,7 @@ static void configure_from_line_edit (lay::Dispatcher *dispatcher, QLineEdit *le
Value value = Value (0);
tl::from_string (tl::to_string (le->text ()), value);
dispatcher->config_set (cfg_name, tl::to_string (value));
lay::indicate_error (le, 0);
lay::indicate_error (le, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
}

View File

@ -46,6 +46,7 @@
#include "layCellTreeModel.h"
#include "layLayoutView.h"
#include "layAbstractMenu.h"
#include "layQtTools.h"
#include "layDialogs.h"
#include "tlExceptions.h"
#include "laybasicConfig.h"
@ -78,6 +79,17 @@ HCPCellTreeWidget::HCPCellTreeWidget (QWidget *parent, const char *name, QWidget
setObjectName (QString::fromUtf8 (name));
}
HCPCellTreeWidget::~HCPCellTreeWidget ()
{
// NOTE: this should not be required, but I got a strange crash on closing the app with Qt 5.12.8
// after using changePersistentIndex inside the model when ~QTreeWidget tried to clean up it's
// persistent indexes and only found a model which was deleted already.
QAbstractItemModel *m = model ();
if (m) {
setModel (0);
delete m;
}
}
bool
HCPCellTreeWidget::event (QEvent *event)
@ -242,7 +254,7 @@ HierarchyControlPanel::HierarchyControlPanel (lay::LayoutView *view, QWidget *pa
mp_search_close_cb->setMaximumSize (QSize (mp_search_close_cb->maximumSize ().width (), mp_search_close_cb->sizeHint ().height () - 4));
connect (mp_search_close_cb, SIGNAL (clicked ()), this, SLOT (search_editing_finished ()));
mp_search_model = 0;
m_search_index = -1;
mp_search_edit_box = new lay::DecoratedLineEdit (mp_search_frame);
mp_search_edit_box->setObjectName (QString::fromUtf8 ("cellview_search_edit_box"));
mp_search_edit_box->set_escape_signal_enabled (true);
@ -264,11 +276,18 @@ HierarchyControlPanel::HierarchyControlPanel (lay::LayoutView *view, QWidget *pa
mp_case_sensitive->setChecked (true);
mp_case_sensitive->setText (tr ("Case sensitive search"));
mp_filter = new QAction (this);
mp_filter->setCheckable (true);
mp_filter->setChecked (false);
mp_filter->setText (tr ("Apply as filter"));
QMenu *m = new QMenu (mp_search_edit_box);
m->addAction (mp_use_regular_expressions);
m->addAction (mp_case_sensitive);
m->addAction (mp_filter);
connect (mp_use_regular_expressions, SIGNAL (triggered ()), this, SLOT (search_edited ()));
connect (mp_case_sensitive, SIGNAL (triggered ()), this, SLOT (search_edited ()));
connect (mp_filter, SIGNAL (triggered ()), this, SLOT (search_edited ()));
mp_search_edit_box->set_clear_button_enabled (true);
mp_search_edit_box->set_options_button_enabled (true);
@ -401,20 +420,20 @@ HierarchyControlPanel::cm_cell_select ()
void
HierarchyControlPanel::search_triggered (const QString &t)
{
mp_search_model = 0;
m_search_index = -1;
lay::HCPCellTreeWidget *w = dynamic_cast<lay::HCPCellTreeWidget *> (sender ());
if (w) {
for (size_t i = 0; i < mp_cell_lists.size (); ++i) {
if (mp_cell_lists [i] == w) {
// Switch the active list for split mode -> CAUTION: this may trigger a search_editing_finished call
select_active (int (i));
mp_search_model = dynamic_cast<lay::CellTreeModel *> (w->model ());
m_search_index = int (i);
break;
}
}
}
if (mp_search_model) {
if (m_search_index >= 0) {
mp_search_close_cb->setChecked (true);
mp_search_frame->show ();
mp_search_edit_box->setText (t);
@ -426,36 +445,43 @@ HierarchyControlPanel::search_triggered (const QString &t)
void
HierarchyControlPanel::search_edited ()
{
bool filter_invalid = false;
QString t = mp_search_edit_box->text ();
for (std::vector <QTreeView *>::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
if ((*v)->model () == mp_search_model) {
if (t.isEmpty ()) {
mp_search_model->clear_locate ();
(*v)->setCurrentIndex (QModelIndex ());
if (m_search_index >= 0 && m_search_index < int (mp_cell_lists.size ())) {
lay::CellTreeModel *search_model = dynamic_cast<lay::CellTreeModel *> (mp_cell_lists [m_search_index]->model ());
search_model->set_filter_mode (mp_filter->isChecked ());
if (t.isEmpty ()) {
search_model->clear_locate ();
mp_cell_lists [m_search_index]->setCurrentIndex (QModelIndex ());
} else {
QModelIndex found = search_model->locate (t.toUtf8 ().constData (), mp_use_regular_expressions->isChecked (), mp_case_sensitive->isChecked (), false);
mp_cell_lists [m_search_index]->setCurrentIndex (found);
if (found.isValid ()) {
mp_cell_lists [m_search_index]->scrollTo (found);
} else {
QModelIndex found = mp_search_model->locate (t.toUtf8 ().constData (), mp_use_regular_expressions->isChecked (), mp_case_sensitive->isChecked (), false);
(*v)->setCurrentIndex (found);
if (found.isValid ()) {
(*v)->scrollTo (found);
}
filter_invalid = true;
}
break;
}
}
lay::indicate_error (mp_search_edit_box, filter_invalid);
}
void
HierarchyControlPanel::search_next ()
{
for (std::vector <QTreeView *>::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
if ((*v)->model () == mp_search_model) {
QModelIndex found = mp_search_model->locate_next ();
if (found.isValid ()) {
(*v)->setCurrentIndex (found);
(*v)->scrollTo (found);
}
break;
{
if (m_search_index >= 0 && m_search_index < int (mp_cell_lists.size ())) {
lay::CellTreeModel *search_model = dynamic_cast<lay::CellTreeModel *> (mp_cell_lists [m_search_index]->model ());
QModelIndex found = search_model->locate_next (mp_cell_lists [m_search_index]->currentIndex ());
if (found.isValid ()) {
mp_cell_lists [m_search_index]->setCurrentIndex (found);
mp_cell_lists [m_search_index]->scrollTo (found);
}
}
}
@ -463,14 +489,12 @@ HierarchyControlPanel::search_next ()
void
HierarchyControlPanel::search_prev ()
{
for (std::vector <QTreeView *>::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
if ((*v)->model () == mp_search_model) {
QModelIndex found = mp_search_model->locate_prev ();
if (found.isValid ()) {
(*v)->setCurrentIndex (found);
(*v)->scrollTo (found);
}
break;
if (m_search_index >= 0 && m_search_index < int (mp_cell_lists.size ())) {
lay::CellTreeModel *search_model = dynamic_cast<lay::CellTreeModel *> (mp_cell_lists [m_search_index]->model ());
QModelIndex found = search_model->locate_prev ();
if (found.isValid ()) {
mp_cell_lists [m_search_index]->setCurrentIndex (found);
mp_cell_lists [m_search_index]->scrollTo (found);
}
}
}
@ -490,15 +514,12 @@ HierarchyControlPanel::search_editing_finished ()
}
// give back the focus to the cell list
for (size_t i = 0; i < mp_cell_lists.size (); ++i) {
if (mp_cell_lists [i]->model () == mp_search_model) {
mp_cell_lists [i]->setFocus ();
break;
}
if (m_search_index >= 0 && m_search_index < int (mp_cell_lists.size ())) {
mp_cell_lists [m_search_index]->setFocus ();
}
mp_search_frame->hide ();
mp_search_model = 0;
m_search_index = -1;
}
void
@ -786,8 +807,12 @@ void
HierarchyControlPanel::do_update_content (int cv_index)
{
// close the search box since we will modify the model
if (m_search_index >= 0 && m_search_index < int (mp_cell_lists.size ())) {
lay::CellTreeModel *search_model = dynamic_cast<lay::CellTreeModel *> (mp_cell_lists [m_search_index]->model ());
search_model->clear_locate ();
}
mp_search_frame->hide ();
mp_search_model = 0;
m_search_index = -1;
unsigned int imin = (cv_index < 0 ? 0 : (unsigned int) cv_index);
unsigned int imax = (cv_index < 0 ? std::numeric_limits <unsigned int>::max () : (unsigned int) cv_index);
@ -1199,7 +1224,7 @@ public:
menu_entries.push_back (lay::menu_item ("cm_cell_show", "show_cell", at, tl::to_string (QObject::tr ("Show"))));
menu_entries.push_back (lay::menu_item ("cm_cell_show_all", "show_all", at, tl::to_string (QObject::tr ("Show All"))));
menu_entries.push_back (lay::separator ("utils_group", at));
menu_entries.push_back (lay::menu_item ("cm_open_current_cell", "open_current", at, tl::to_string (QObject::tr ("Where Am I?"))));
menu_entries.push_back (lay::menu_item ("cm_open_current_cell", "open_current", at, tl::to_string (QObject::tr ("Where am I?"))));
menu_entries.push_back (lay::separator ("file_group", at));
menu_entries.push_back (lay::menu_item ("cm_save_current_cell_as", "save_cell_as:hide_vo", at, tl::to_string (QObject::tr ("Save Selected Cells As"))));
}

View File

@ -66,6 +66,7 @@ Q_OBJECT
public:
HCPCellTreeWidget (QWidget *parent, const char *name, QWidget *key_event_receiver);
~HCPCellTreeWidget ();
signals:
void cell_clicked (const QModelIndex &);
@ -298,7 +299,8 @@ private:
lay::DecoratedLineEdit *mp_search_edit_box;
QAction *mp_case_sensitive;
QAction *mp_use_regular_expressions;
CellTreeModel *mp_search_model;
QAction *mp_filter;
int m_search_index;
QFrame *mp_search_frame;
QCheckBox *mp_search_close_cb;
QSplitter *mp_splitter;

View File

@ -34,6 +34,7 @@
#include "layDialogs.h"
#include "layLayoutCanvas.h"
#include "layAbstractMenu.h"
#include "layQtTools.h"
#include "tlExceptions.h"
#include "tlInternational.h"
#include "tlAssert.h"
@ -203,12 +204,10 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage
mp_view (view),
m_needs_update (true),
m_tabs_need_update (true),
m_force_update_hidden_flags (true),
m_in_update (false),
m_phase (0),
m_do_update_content_dm (this, &LayerControlPanel::do_update_content),
m_hide_empty_layers (false),
m_test_shapes_in_view (false),
m_do_update_hidden_flags_dm (this, &LayerControlPanel::do_update_hidden_flags),
m_no_stipples (false)
{
setObjectName (QString::fromUtf8 (name));
@ -269,11 +268,18 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage
mp_case_sensitive->setChecked (true);
mp_case_sensitive->setText (tr ("Case sensitive search"));
mp_filter = new QAction (this);
mp_filter->setCheckable (true);
mp_filter->setChecked (false);
mp_filter->setText (tr ("Apply as filter"));
QMenu *m = new QMenu (mp_search_edit_box);
m->addAction (mp_use_regular_expressions);
m->addAction (mp_case_sensitive);
m->addAction (mp_filter);
connect (mp_use_regular_expressions, SIGNAL (triggered ()), this, SLOT (search_edited ()));
connect (mp_case_sensitive, SIGNAL (triggered ()), this, SLOT (search_edited ()));
connect (mp_filter, SIGNAL (triggered ()), this, SLOT (search_edited ()));
mp_search_edit_box->set_clear_button_enabled (true);
mp_search_edit_box->set_options_button_enabled (true);
@ -370,6 +376,8 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage
m_no_stipples_label->setPixmap (QPixmap (QString::fromUtf8 (":/important.png")));
m_no_stipples_label->setToolTip (tr ("Stipples are disabled - unselect \"View/Show Layers Without Fill\" to re-enable them"));
ltb->addWidget (m_no_stipples_label);
connect (mp_model, SIGNAL (hidden_flags_need_update ()), this, SLOT (update_hidden_flags ()));
}
LayerControlPanel::~LayerControlPanel ()
@ -1126,6 +1134,10 @@ LayerControlPanel::search_edited ()
return;
}
mp_model->set_filter_mode (mp_filter->isChecked ());
bool filter_invalid = false;
QString t = mp_search_edit_box->text ();
if (t.isEmpty ()) {
mp_model->clear_locate ();
@ -1135,8 +1147,12 @@ LayerControlPanel::search_edited ()
mp_layer_list->setCurrentIndex (found);
if (found.isValid ()) {
mp_layer_list->scrollTo (found);
} else {
filter_invalid = true;
}
}
lay::indicate_error (mp_search_edit_box, filter_invalid);
}
void
@ -1642,27 +1658,28 @@ LayerControlPanel::set_text_color (QColor c)
mp_model->set_text_color (c);
}
void
void
LayerControlPanel::update_hidden_flags ()
{
m_do_update_hidden_flags_dm ();
}
void
LayerControlPanel::set_hide_empty_layers (bool f)
{
if (f != m_hide_empty_layers) {
m_hide_empty_layers = f;
m_force_update_hidden_flags = true;
m_do_update_content_dm ();
}
mp_model->set_hide_empty_layers (f);
}
bool
LayerControlPanel::hide_empty_layers ()
{
return mp_model->get_hide_empty_layers ();
}
void
LayerControlPanel::set_test_shapes_in_view (bool f)
{
if (f != m_test_shapes_in_view) {
m_test_shapes_in_view = f;
mp_model->set_test_shapes_in_view (f);
if (m_hide_empty_layers) {
m_force_update_hidden_flags = true;
}
m_do_update_content_dm ();
}
mp_model->set_test_shapes_in_view (f);
}
void
@ -1707,7 +1724,6 @@ LayerControlPanel::cancel_updates ()
void
LayerControlPanel::end_updates ()
{
m_force_update_hidden_flags = true;
do_update_content ();
}
@ -1721,7 +1737,7 @@ LayerControlPanel::set_phase (int phase)
}
static void
set_hidden_flags_within_view_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent, bool hide_empty)
set_hidden_flags_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent)
{
int rows = model->rowCount (parent);
for (int r = 0; r < rows; ++r) {
@ -1730,7 +1746,7 @@ set_hidden_flags_within_view_rec (LayerTreeModel *model, QTreeView *tree_view, c
if (! model->hasChildren (index)) {
if (hide_empty && model->empty_within_view_predicate (index)) {
if (model->is_hidden (index)) {
tree_view->setRowHidden (r, parent, true);
} else {
tree_view->setRowHidden (r, parent, false);
@ -1738,43 +1754,33 @@ set_hidden_flags_within_view_rec (LayerTreeModel *model, QTreeView *tree_view, c
} else {
tree_view->setRowHidden (r, parent, false);
set_hidden_flags_within_view_rec (model, tree_view, index, hide_empty);
}
}
}
static void
set_hidden_flags_rec (LayerTreeModel *model, QTreeView *tree_view, const QModelIndex &parent, bool hide_empty)
{
int rows = model->rowCount (parent);
for (int r = 0; r < rows; ++r) {
QModelIndex index = model->index (r, 0, parent);
if (! model->hasChildren (index)) {
if (hide_empty && model->empty_predicate (index)) {
tree_view->setRowHidden (r, parent, true);
} else {
tree_view->setRowHidden (r, parent, false);
}
} else {
tree_view->setRowHidden (r, parent, false);
set_hidden_flags_rec (model, tree_view, index, hide_empty);
set_hidden_flags_rec (model, tree_view, index);
}
}
}
void
LayerControlPanel::do_update_hidden_flags ()
{
set_hidden_flags_rec (mp_model, mp_layer_list, QModelIndex ());
// scroll the current index into view if it was not visible before
QModelIndex current = mp_layer_list->currentIndex ();
if (current.isValid ()) {
QModelIndex parent = mp_layer_list->model ()->parent (current);
if (! mp_layer_list->isRowHidden (current.row (), parent)) {
QRect visual_rect = mp_layer_list->visualRect (current);
if (! visual_rect.intersects (mp_layer_list->viewport ()->rect ())) {
mp_layer_list->scrollTo (current, QAbstractItemView::PositionAtCenter);
}
}
}
}
void
LayerControlPanel::do_update_content ()
{
// clear search. TODO: update search instead of clearing
mp_search_edit_box->clear ();
mp_model->clear_locate();
mp_model->set_phase (m_phase);
if (m_tabs_need_update) {
@ -1853,48 +1859,21 @@ LayerControlPanel::do_update_content ()
m_needs_update = false;
} else if (m_needs_update) {
m_needs_update = false;
bool has_children = false;
for (lay::LayerPropertiesConstIterator l = mp_view->begin_layers (); l != mp_view->end_layers () && ! has_children; ++l) {
if (l->has_children ()) {
has_children = true;
}
}
mp_layer_list->setRootIsDecorated (has_children);
mp_layer_list->reset ();
} else {
if (m_needs_update) {
m_needs_update = false;
bool has_children = false;
for (lay::LayerPropertiesConstIterator l = mp_view->begin_layers (); l != mp_view->end_layers () && ! has_children; ++l) {
if (l->has_children ()) {
has_children = true;
}
}
mp_layer_list->setRootIsDecorated (has_children);
mp_layer_list->reset ();
} else {
mp_model->signal_data_changed (); // this makes the view redraw the data
}
}
if (m_hide_empty_layers || m_force_update_hidden_flags) {
m_force_update_hidden_flags = false;
if (m_test_shapes_in_view) {
set_hidden_flags_within_view_rec (mp_model, mp_layer_list, QModelIndex (), m_hide_empty_layers);
} else {
set_hidden_flags_rec (mp_model, mp_layer_list, QModelIndex (), m_hide_empty_layers);
}
// scroll the current index into view if it was not visible before
QModelIndex current = mp_layer_list->currentIndex ();
if (current.isValid ()) {
QModelIndex parent = mp_layer_list->model ()->parent (current);
if (! mp_layer_list->isRowHidden (current.row (), parent)) {
QRect visual_rect = mp_layer_list->visualRect (current);
if (! visual_rect.intersects (mp_layer_list->viewport ()->rect ())) {
mp_layer_list->scrollTo (current, QAbstractItemView::PositionAtCenter);
}
}
}
mp_model->signal_data_changed (); // this makes the view redraw the data
}
}
@ -1975,7 +1954,7 @@ LayerControlPanel::redo (db::Op *op)
void
LayerControlPanel::signal_vp_changed ()
{
if (m_test_shapes_in_view) {
if (mp_model->get_test_shapes_in_view ()) {
update_required (1);
}
}
@ -2028,7 +2007,7 @@ LayerControlPanel::update_required (int f)
}
if ((f & 3) != 0) {
m_force_update_hidden_flags = true;
m_do_update_hidden_flags_dm ();
}
m_do_update_content_dm ();

View File

@ -184,10 +184,7 @@ public:
/**
* @brief Get the "hide empty layers" flag
*/
bool hide_empty_layers ()
{
return m_hide_empty_layers;
}
bool hide_empty_layers ();
/**
* @brief Set the "test_shapes_in_view" flag
@ -201,7 +198,7 @@ public:
*/
bool test_shapes_in_view ()
{
return m_test_shapes_in_view;
return mp_model->get_test_shapes_in_view ();
}
/**
@ -333,6 +330,9 @@ public slots:
void search_next ();
void search_prev ();
private slots:
void update_hidden_flags ();
private:
QTabBar *mp_tab_bar;
LCPTreeWidget *mp_layer_list;
@ -341,19 +341,17 @@ private:
lay::LayoutView *mp_view;
bool m_needs_update;
bool m_tabs_need_update;
bool m_force_update_hidden_flags;
bool m_in_update;
std::vector<size_t> m_new_sel;
int m_phase;
tl::DeferredMethod<LayerControlPanel> m_do_update_content_dm;
bool m_hide_empty_layers;
bool m_test_shapes_in_view;
tl::DeferredMethod<LayerControlPanel> m_do_update_content_dm, m_do_update_hidden_flags_dm;
std::set<unsigned int> m_expanded;
bool m_no_stipples;
QLabel *m_no_stipples_label;
lay::DecoratedLineEdit *mp_search_edit_box;
QAction *mp_case_sensitive;
QAction *mp_use_regular_expressions;
QAction *mp_filter;
QFrame *mp_search_frame;
QCheckBox *mp_search_close_cb;
@ -369,6 +367,7 @@ private:
void signal_vp_changed ();
void do_update_content ();
void do_update_hidden_flags ();
void do_delete ();
void do_copy ();
void recover ();

View File

@ -180,7 +180,7 @@ EmptyWithinViewCache::determine_empty_layers (const db::Layout *layout, unsigned
LayerTreeModel::LayerTreeModel (QWidget *parent, lay::LayoutView *view)
: QAbstractItemModel (parent),
mp_view (view), m_id_start (0), m_id_end (0), m_phase ((unsigned int) -1), m_test_shapes_in_view (false)
mp_view (view), m_filter_mode (false), m_id_start (0), m_id_end (0), m_phase ((unsigned int) -1), m_test_shapes_in_view (false), m_hide_empty_layers (false)
{
// .. nothing yet ..
}
@ -210,6 +210,37 @@ LayerTreeModel::set_text_color (QColor color)
signal_data_changed ();
}
void
LayerTreeModel::set_test_shapes_in_view (bool f)
{
if (m_test_shapes_in_view != f) {
m_test_shapes_in_view = f;
if (m_hide_empty_layers) {
emit hidden_flags_need_update ();
}
signal_data_changed ();
}
}
void
LayerTreeModel::set_hide_empty_layers (bool f)
{
if (m_hide_empty_layers != f) {
m_hide_empty_layers = f;
// we actually can't do this ourselves.
emit hidden_flags_need_update ();
}
}
void
LayerTreeModel::set_filter_mode (bool f)
{
if (f != m_filter_mode) {
m_filter_mode = f;
emit hidden_flags_need_update ();
}
}
void
LayerTreeModel::set_background_color (QColor background)
{
@ -288,6 +319,10 @@ LayerTreeModel::clear_locate ()
m_selected_ids.clear ();
signal_data_changed ();
if (m_filter_mode) {
emit hidden_flags_need_update ();
}
}
QModelIndex
@ -358,6 +393,10 @@ LayerTreeModel::locate (const char *name, bool glob_pattern, bool case_sensitive
signal_data_changed ();
if (m_filter_mode) {
emit hidden_flags_need_update ();
}
m_current_index = m_selected_indexes.begin ();
if (m_current_index == m_selected_indexes.end ()) {
return QModelIndex ();
@ -481,6 +520,22 @@ single_bitmap_to_image (const lay::ViewOp &view_op, lay::Bitmap &bitmap,
lay::bitmaps_to_image (view_ops, pbitmaps, dither_pattern, line_styles, pimage, width, height, false, 0);
}
bool
LayerTreeModel::is_hidden (const QModelIndex &index) const
{
if (m_filter_mode && ! m_selected_ids.empty () && m_selected_ids.find (size_t (index.internalPointer ())) == m_selected_ids.end ()) {
return true;
}
if (! m_hide_empty_layers) {
return false;
} else if (m_test_shapes_in_view) {
return empty_within_view_predicate (index);
} else {
return empty_predicate (index);
}
}
bool
LayerTreeModel::empty_predicate (const QModelIndex &index) const
{

View File

@ -126,21 +126,9 @@ public:
lay::LayerPropertiesConstIterator iterator (const QModelIndex &index) const;
/**
* @brief Get a flag indicating that a layer is empty
* @brief Get a flag indicating that an entry is hidden
*/
bool empty_predicate (const QModelIndex &index) const;
/**
* @brief Get a flag indicating that a layer does not have shapes within the shown area
*/
bool empty_within_view_predicate (const QModelIndex &index) const;
/**
* @brief Set the non-empty layers (the "uint" for the layer iterators) for the "test shapes is view" mode
*
* @return True, if a change has been made.
*/
bool set_non_empty_layers (const std::set <size_t> &non_empty_layers);
bool is_hidden (const QModelIndex &index) const;
/**
* @brief Set the animation phase
@ -201,13 +189,42 @@ public:
void clear_locate ();
/**
* @brief Set the test_shapes_in_view flag
*
* This method does not issue a data changed signal. This has to be done somewhere else.
* @brief Sets a flag indicating whether to test shapes in view for highlighting non-empty layers
*/
void set_test_shapes_in_view (bool f)
void set_test_shapes_in_view (bool f);
/**
* @brief Gets a flag indicating whether to test shapes in view for highlighting non-empty layers
*/
bool get_test_shapes_in_view ()
{
m_test_shapes_in_view = f;
return m_test_shapes_in_view;
}
/**
* @brief Sets the flag indicating whether to hide empty layers
*/
void set_hide_empty_layers (bool f);
/**
* @brief Gets the flag indicating whether to hide empty layers
*/
bool get_hide_empty_layers () const
{
return m_hide_empty_layers;
}
/**
* @brief Sets a flag indicating whether selected indexes are filtered or highlighted
*/
void set_filter_mode (bool f);
/**
* @brief Gets a flag indicating whether selected indexes are filtered or highlighted
*/
bool get_filter_mode () const
{
return m_filter_mode;
}
/**
@ -220,11 +237,19 @@ public:
*/
void signal_layer_changed ();
signals:
/**
* @brief This signal is emitted to indicate
*/
void hidden_flags_need_update ();
private:
lay::LayoutView *mp_view;
bool m_filter_mode;
size_t m_id_start, m_id_end;
unsigned int m_phase;
bool m_test_shapes_in_view;
bool m_hide_empty_layers;
QFont m_font;
QColor m_text_color, m_background_color;
mutable EmptyWithinViewCache m_test_shapes_cache;
@ -232,6 +257,16 @@ private:
std::vector <QModelIndex> m_selected_indexes;
std::vector <QModelIndex>::const_iterator m_current_index;
/**
* @brief Get a flag indicating that a layer is empty
*/
bool empty_predicate (const QModelIndex &index) const;
/**
* @brief Get a flag indicating that a layer does not have shapes within the shown area
*/
bool empty_within_view_predicate (const QModelIndex &index) const;
void search_children (const tl::GlobPattern &pattern, const QModelIndex &parent, bool recurse);
};

View File

@ -262,11 +262,18 @@ LibrariesView::LibrariesView (lay::LayoutView *view, QWidget *parent, const char
mp_case_sensitive->setChecked (true);
mp_case_sensitive->setText (tr ("Case sensitive search"));
mp_filter = new QAction (this);
mp_filter->setCheckable (true);
mp_filter->setChecked (false);
mp_filter->setText (tr ("Apply as filter"));
QMenu *m = new QMenu (mp_search_edit_box);
m->addAction (mp_use_regular_expressions);
m->addAction (mp_case_sensitive);
m->addAction (mp_filter);
connect (mp_use_regular_expressions, SIGNAL (triggered ()), this, SLOT (search_edited ()));
connect (mp_case_sensitive, SIGNAL (triggered ()), this, SLOT (search_edited ()));
connect (mp_filter, SIGNAL (triggered ()), this, SLOT (search_edited ()));
mp_search_edit_box->set_clear_button_enabled (true);
mp_search_edit_box->set_options_button_enabled (true);
@ -382,6 +389,7 @@ LibrariesView::search_edited ()
for (std::vector <QTreeView *>::const_iterator v = mp_cell_lists.begin (); v != mp_cell_lists.end (); ++v) {
if ((*v)->model () == mp_search_model) {
mp_search_model->set_filter_mode (mp_filter->isChecked ());
if (t.isEmpty ()) {
mp_search_model->clear_locate ();
(*v)->setCurrentIndex (QModelIndex ());

View File

@ -242,6 +242,7 @@ private:
lay::DecoratedLineEdit *mp_search_edit_box;
QAction *mp_case_sensitive;
QAction *mp_use_regular_expressions;
QAction *mp_filter;
CellTreeModel *mp_search_model;
QFrame *mp_search_frame;
QCheckBox *mp_search_close_cb;

View File

@ -162,22 +162,48 @@ restore_dialog_state (QWidget *dialog, const std::string &s, bool with_section_s
void
indicate_error (QWidget *le, const tl::Exception *ex)
{
if (ex) {
indicate_error (le, true);
le->setToolTip (tl::to_qstring (ex->msg ()));
} else {
indicate_error (le, false);
le->setToolTip (QString ());
}
}
void
indicate_error (QWidget *le, bool f)
{
// by the way, update the foreground color of the cell edit box as well (red, if not valid)
QPalette pl = le->palette ();
if (ex) {
if (f) {
pl.setColor (QPalette::Active, QPalette::Text, Qt::red);
pl.setColor (QPalette::Active, QPalette::Base, QColor (Qt::red).lighter (180));
le->setToolTip (tl::to_qstring (ex->msg ()));
} else {
QWidget *pw = dynamic_cast<QWidget *> (le->parent ());
tl_assert (pw != 0);
pl.setColor (QPalette::Active, QPalette::Text, pw->palette ().color (QPalette::Text));
pl.setColor (QPalette::Active, QPalette::Base, pw->palette ().color (QPalette::Base));
le->setToolTip (QString ());
}
le->setPalette (pl);
}
#if QT_VERSION < 0x050000
SignalBlocker::SignalBlocker (QWidget *w)
: mp_widget (w)
{
m_state = mp_widget->blockSignals (true);
}
SignalBlocker::~SignalBlocker ()
{
mp_widget->blockSignals (m_state);
}
#endif
}

View File

@ -31,6 +31,7 @@
class QLabel;
class QWidget;
class QObject;
class QSignalBlocker;
namespace tl
{
@ -76,6 +77,32 @@ LAYBASIC_PUBLIC void register_help_handler (QObject *object, const char *slot, c
*/
LAYBASIC_PUBLIC void indicate_error (QWidget *le, const tl::Exception *ex);
/**
* @brief Configures a QLineEdit or other widget to indicate an error
*/
LAYBASIC_PUBLIC void indicate_error (QWidget *le, bool error);
#if QT_VERSION < 0x050000
// Provide missing QSignalBlocker for Qt4
class LAYBASIC_PUBLIC SignalBlocker
{
public:
SignalBlocker (QWidget *w);
~SignalBlocker ();
private:
QWidget *mp_widget;
bool m_state;
};
#else
typedef QSignalBlocker SignalBlocker;
#endif
} // namespace lay
#endif

View File

@ -400,7 +400,7 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con
ex.read (v);
ex.expect_end ();
data->set_net_property_name (v);
indicate_error (net_prop_name, 0);
indicate_error (net_prop_name, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
indicate_error (net_prop_name, &ex);
has_error = true;
@ -414,7 +414,7 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con
ex.read (v);
ex.expect_end ();
data->set_inst_property_name (v);
indicate_error (inst_prop_name, 0);
indicate_error (inst_prop_name, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
indicate_error (inst_prop_name, &ex);
has_error = true;
@ -428,7 +428,7 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con
ex.read (v);
ex.expect_end ();
data->set_pin_property_name (v);
indicate_error (pin_prop_name, 0);
indicate_error (pin_prop_name, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
indicate_error (pin_prop_name, &ex);
has_error = true;
@ -441,7 +441,7 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con
tl::Extractor ex (s.c_str ());
lp.read (ex);
ex.expect_end ();
indicate_error (outline_layer, 0);
indicate_error (outline_layer, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
indicate_error (outline_layer, &ex);
has_error = true;
@ -454,7 +454,7 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con
tl::Extractor ex (s.c_str ());
lp.read (ex);
ex.expect_end ();
indicate_error (region_layer, 0);
indicate_error (region_layer, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
indicate_error (region_layer, &ex);
has_error = true;
@ -467,7 +467,7 @@ LEFDEFReaderOptionsEditor::commit (db::FormatSpecificReaderOptions *options, con
tl::Extractor ex (s.c_str ());
lp.read (ex);
ex.expect_end ();
indicate_error (placement_blockage_layer, 0);
indicate_error (placement_blockage_layer, (tl::Exception *) 0);
} catch (tl::Exception &ex) {
indicate_error (placement_blockage_layer, &ex);
has_error = true;