diff --git a/include/nana/gui/place.hpp b/include/nana/gui/place.hpp index 56f27f34..f90298ab 100644 --- a/include/nana/gui/place.hpp +++ b/include/nana/gui/place.hpp @@ -107,22 +107,10 @@ namespace nana class error :public std::invalid_argument { public: - error( const std::string& what, - const place& plc, - std::string field = "unknown", - std::string::size_type pos = std::string::npos) - - : std::invalid_argument{ "Place error " + what - + " from widget " + API::window_caption(plc.window_handle()).substr(0,80) - + " in fleld " + field - + ( pos == std::string::npos ? "" : "at at position " + std::to_string(pos) ) - + "in div_text:\n" + plc.div()}, - base_what { what }, - owner_caption{ API::window_caption(plc.window_handle()).substr(0,80) }, - field { field }, - div_text { plc.div() }, - pos { pos } - {} + error( const std::string& what, + const place& plc, + std::string field = "unknown", + std::string::size_type pos = std::string::npos); std::string base_what; std::string owner_caption; ///< truncate caption (title) of the "placed" widget std::string div_text; ///< involved div_text diff --git a/source/gui/place.cpp b/source/gui/place.cpp index d334a579..c932f78f 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -61,9 +61,11 @@ namespace nana const tokenizer& tok) : std::invalid_argument{ what + " from tokenizer " }, - pos{static_cast(tok.sp_ - tok.divstr_)} + pos{tok.pos()}, + div_str(tok.divstr_) {} std::string::size_type pos; + std::string div_str; }; enum class token @@ -105,9 +107,9 @@ namespace nana return parameters_; } - std::size_t pos() const noexcept + std::string::size_type pos() const noexcept { - return (sp_ - divstr_); + return static_cast(sp_ - divstr_); } token read() @@ -227,7 +229,7 @@ namespace nana return token::number; } else - throw("invalid character '" + std::string(1, *sp_) + "'", *this); + throw error("invalid character '" + std::string(1, *sp_) + "'", *this); break; default: if ('0' <= *sp_ && *sp_ <= '9') @@ -349,7 +351,7 @@ namespace nana return token::identifier; } - throw("invalid character '" + std::string(1, *sp_) + "'", *this); + throw error("invalid character '" + std::string(1, *sp_) + "'", *this); return token::error; //Useless, just for syntax correction. } private: @@ -472,7 +474,7 @@ namespace nana return 0; } private: - const char* divstr_{}; + const char* divstr_{}; const char* sp_{}; std::string idstr_; number_t number_; @@ -609,13 +611,16 @@ namespace nana /// usefull ?? struct error : std::invalid_argument { - error(std::string what, - const implement& impl) + error(std::string what, + std::string field = "unknown", + std::string::size_type pos = std::string::npos) - : std::invalid_argument{ what + " from implementation " }/*, - pos{ static_cast(tok.sp_ - tok.divstr_) }*/ + : std::invalid_argument{ what + " from place implementation " }, + pos{ pos }, + field { field.empty() ? "unnamed" : field } {} std::string::size_type pos; + std::string field; }; class field_gather; class field_dock; @@ -2007,11 +2012,11 @@ namespace nana return; auto fieldstr = div.substr(bound.first, bound.second - bound.first); - _m_remove_attr(fieldstr, "weight"); + _m_remove_attr(fieldstr, "weight"); /// \todo and higth, width ? std::string::size_type tag_pos{ left ? div.find('<', bound.second + 2) : div.rfind('>', bound.first - 2) }; if (div.npos == tag_pos) - throw place::error("please report an issue: unable to update division " + div, impl_-> ); + throw place::implement::error("please report an issue: the splitter was unable to update division " + div, name); auto other_bound = get_field_boundary(div, tag_pos); @@ -2727,7 +2732,7 @@ namespace nana return static_cast(arg.real()); const char* pos_strs[] = { "1st", "2nd", "3rd", "4th" }; - throw std::invalid_argument("nana.place: the type of the " + std::string{pos_strs[pos]} +"th parameter for collapse should be integer."); + throw place_parts::tokenizer::error("the type of the " + std::string{pos_strs[pos]} +" parameter for collapse should be integer.", tknizer); } //implicitly_started indicates whether the field in div-text starts without < mark. @@ -2755,82 +2760,83 @@ namespace nana bool invisible = false; token tk = token::eof; - for (tk = tknizer.read(); (tk != token::eof && tk != token::div_end); tk = tknizer.read()) - { - switch (tk) + try { + for (tk = tknizer.read(); (tk != token::eof && tk != token::div_end); tk = tknizer.read()) { - case token::dock: - if (token::eof != div_type && token::dock != div_type) - throw std::invalid_argument("nana.place: conflict of div type at " + std::to_string(tknizer.pos())); - - div_type = token::dock; - break; - case token::fit: - fit = fit_policy::both; - break; - case token::hfit: - case token::vfit: - fit = (token::hfit == tk ? fit_policy::horz : fit_policy::vert); - fit_parameters = tknizer.reparray(); - break; - case token::splitter: - //Ignore the splitter when there is not a division. - if (!children.empty() && (division::kind::splitter != children.back()->kind_of_division)) + switch (tk) { - auto splitter = new div_splitter(tknizer.number(), this); - children.back()->div_next = splitter; + case token::dock: + if (token::eof != div_type && token::dock != div_type) + throw std::invalid_argument("conflict of div type -expected dock type-"); - //Hides the splitter if its left leaf is undisplayed. - if (!children.back()->display) - splitter->display = false; + div_type = token::dock; + break; + case token::fit: + fit = fit_policy::both; + break; + case token::hfit: + case token::vfit: + fit = (token::hfit == tk ? fit_policy::horz : fit_policy::vert); + fit_parameters = tknizer.reparray(); + break; + case token::splitter: + //Ignore the splitter when there is not a division. + if (!children.empty() && (division::kind::splitter != children.back()->kind_of_division)) + { + auto splitter = new div_splitter(tknizer.number(), this); + children.back()->div_next = splitter; - children.emplace_back(std::unique_ptr{ splitter }); + //Hides the splitter if its left leaf is undisplayed. + if (!children.back()->display) + splitter->display = false; + + children.emplace_back(std::unique_ptr{ splitter }); + } + break; + case token::div_start: + { + auto div = scan_div(tknizer, false, ignore_duplicate); + if (!children.empty()) + { + //Hides the splitter if its right leaf is undisplayed. + if ((children.back()->kind_of_division == division::kind::splitter) && !div->display) + children.back()->display = false; + + children.back()->div_next = div.get(); + } + + children.emplace_back(std::move(div)); } break; - case token::div_start: - { - auto div = scan_div(tknizer, false, ignore_duplicate); - if (!children.empty()) - { - //Hides the splitter if its right leaf is undisplayed. - if ((children.back()->kind_of_division == division::kind::splitter) && !div->display) - children.back()->display = false; - - children.back()->div_next = div.get(); - } - - children.emplace_back(std::move(div)); - } - break; - case token::switchable: - div_type = token::switchable; - break; - case token::vert: - div_type = tk; - break; - case token::grid: - div_type = tk; - switch (tknizer.read()) - { - case token::number: - array.push_back(tknizer.number()); - array.push_back(tknizer.number()); + case token::switchable: + div_type = token::switchable; break; - case token::array: - tknizer.array().swap(array); + case token::vert: + div_type = tk; break; - case token::reparray: - array.push_back(tknizer.reparray().at(0)); - array.push_back(tknizer.reparray().at(1)); + case token::grid: + div_type = tk; + switch (tknizer.read()) + { + case token::number: + array.push_back(tknizer.number()); + array.push_back(tknizer.number()); + break; + case token::array: + tknizer.array().swap(array); + break; + case token::reparray: + array.push_back(tknizer.reparray().at(0)); + array.push_back(tknizer.reparray().at(1)); + break; + default: + break; + } break; - default: - break; - } - break; - case token::collapse: + case token::collapse: { if (tknizer.parameters().size() != 4) - throw std::invalid_argument("nana.place: collapse requires 4 parameters."); + throw std::invalid_argument("collapse requires 4 parameters"); ::nana::rectangle col{ get_parameter(tknizer, 0), @@ -2845,7 +2851,7 @@ namespace nana { //Overwrite if a exist_col in collapses has same position as the col. bool use_col = true; - for (auto & exist_col : collapses) + for (auto& exist_col : collapses) { if (exist_col.x == col.x && exist_col.y == col.y) { @@ -2859,7 +2865,7 @@ namespace nana } } break; - case token::weight: case token::min_px: case token::max_px: case token::width: case token::height: + case token::weight: case token::min_px: case token::max_px: case token::width: case token::height: { auto n = tknizer.number(); //If n is the type of real, convert it to integer. @@ -2870,7 +2876,7 @@ namespace nana switch (tk) { case token::weight: weight = n; weight_type = token::weight; break; // we could detect errors here (redefinitions and duplicates) - case token::width : weight = n; weight_type = token::width ; break; + case token::width: weight = n; weight_type = token::width; break; case token::height: weight = n; weight_type = token::height; break; case token::min_px: min_px = n; break; case token::max_px: max_px = n; break; @@ -2878,228 +2884,246 @@ namespace nana } } break; - case token::arrange: - arrange = tknizer.reparray(); - break; - case token::gap: - gap = tknizer.reparray(); - break; - case token::margin: - margin.clear(); - switch (tknizer.read()) - { - case token::number: - margin.push(tknizer.number(), true); + case token::arrange: + arrange = tknizer.reparray(); break; - case token::array: - margin.set_array(tknizer.array()); + case token::gap: + gap = tknizer.reparray(); break; - case token::reparray: - for (std::size_t i = 0; i < 4; ++i) + case token::margin: + margin.clear(); + switch (tknizer.read()) { - auto n = tknizer.reparray().at(i); - if (n.empty()) n.assign(0); - margin.push(n); - } - break; - default: - break; - } - break; - case token::identifier: - name = tknizer.idstr(); - break; - case token::left: - div_dir = ::nana::direction::west; break; - case token::right: - div_dir = ::nana::direction::east; break; - case token::top: - div_dir = ::nana::direction::north; break; - case token::bottom: - div_dir = ::nana::direction::south; break; - case token::undisplayed: - undisplayed = true; break; - case token::invisible: - invisible = true; break; - default: break; - } - } - - if (implicitly_started && (tk == token::div_end)) - throw std::invalid_argument("nana.place: the div-text ends prematurely at " + std::to_string(tknizer.pos())); - - field_gather * attached_field = nullptr; - - //find the field with specified name. - //the field may not be created. - auto i = fields.find(name); - if (fields.end() != i) - { - attached_field = i->second; - //the field is attached to a division, it means there is another division with same name. - if (attached_field->attached) - { - //The fields are allowed to have a same name. E.g. - //place.div("A "); - //place.modify("A", ""); Here the same name B must be allowed, otherwise it throws runtime error. - - bool allow_same_name = false; - if (!ignore_duplicate.empty()) - { - auto f = attached_field->attached->div_owner; - while (f) - { - if (f->name == ignore_duplicate) + case token::number: + margin.push(tknizer.number(), true); + break; + case token::array: + margin.set_array(tknizer.array()); + break; + case token::reparray: + for (std::size_t i = 0; i < 4; ++i) { - allow_same_name = true; - break; + auto n = tknizer.reparray().at(i); + if (n.empty()) n.assign(0); + margin.push(n); } - - f = f->div_owner; + break; + default: + break; } + break; + case token::identifier: + name = tknizer.idstr(); + break; + case token::left: + div_dir = ::nana::direction::west; break; + case token::right: + div_dir = ::nana::direction::east; break; + case token::top: + div_dir = ::nana::direction::north; break; + case token::bottom: + div_dir = ::nana::direction::south; break; + case token::undisplayed: + undisplayed = true; break; + case token::invisible: + invisible = true; break; + default: break; } - - if (!allow_same_name) - throw std::runtime_error("place, the name '" + name + "' is redefined."); - } - } - - token unmatch = token::width; - switch (div_type) - { - case token::eof: // "horizontal" div - case token::vert: // "vertical" div - if(token::eof == div_type) - unmatch = token::height; - - for (auto& ch : children) - if (ch->weigth_type == unmatch) - throw std::invalid_argument("nana.place: unmatch vertical-height/horizontal-width between division '" - +name+"' and children division '" + ch->name); - - div.reset(new div_arrange(token::vert == div_type, std::move(name), std::move(arrange))); - break; - case token::grid: - { - std::unique_ptr p(new div_grid(std::move(name), std::move(arrange), std::move(collapses))); - - if (array.size()) - p->dimension.first = array[0].integer(); - - if (array.size() > 1) - p->dimension.second = array[1].integer(); - - if (0 == p->dimension.first) - p->dimension.first = 1; - - if (0 == p->dimension.second) - p->dimension.second = 1; - - p->revise_collapses(); - div = std::move(p); - } - break; - case token::dock: - div.reset(new div_dock(std::move(name), this)); - break; - case token::switchable: - div.reset(new div_switchable(std::move(name), this)); - break; - default: - throw std::invalid_argument("nana.place: invalid division type."); - } - div->weigth_type = weight_type; - - //Requirements for min/max - //1, min and max != negative - //2, max >= min - if (min_px.is_negative()) min_px.reset(); - if (max_px.is_negative()) max_px.reset(); - if ((!min_px.empty()) && (!max_px.empty()) && (min_px.get_value(100) > max_px.get_value(100))) - { - min_px.reset(); - max_px.reset(); - } - - if (!min_px.empty()) - div->min_px = min_px; - - if (!max_px.empty()) - div->max_px = max_px; - - if ((!min_px.empty()) && (!weight.empty()) && (weight.get_value(100) < min_px.get_value(100))) - weight.reset(); - - if ((!max_px.empty()) && (!weight.empty()) && (weight.get_value(100) > max_px.get_value(100))) - weight.reset(); - - if (!weight.empty()) - div->weight = weight; - - div->gap = std::move(gap); - - //attach the field to the division - div->field = attached_field; - if (attached_field) - { - //Replaces the previous div with the new div which is allowed to have a same name. - - //Detaches the field from the previous div. - if (attached_field->attached) - attached_field->attached->field = nullptr; - - //Attaches new div - attached_field->attached = div.get(); - } - - if (children.size()) - { - if (division::kind::splitter == children.back()->kind_of_division) - { - children.pop_back(); - if (children.size()) - children.back()->div_next = nullptr; } - for (auto& child : children) - { - child->div_owner = div.get(); - if (division::kind::splitter == child->kind_of_division) - dynamic_cast(*child).direction(div_type != token::vert); - } + if (implicitly_started && (tk == token::div_end)) + throw std::invalid_argument("the div-text ends prematurely"); - if (token::dock == div_type) + field_gather * attached_field = nullptr; + + //find the field with specified name. + //the field may not be created. + auto i = fields.find(name); + if (fields.end() != i) { - //adjust these children for dock division - std::vector> adjusted_children; - for (auto & child : children) + attached_field = i->second; + //the field is attached to a division, it means there is another division with same name. + if (attached_field->attached) { - auto dockpn = new div_dockpane(std::move(child->name), this, child->dir); - dockpn->div_owner = child->div_owner; - dockpn->weight = child->weight; - adjusted_children.emplace_back(std::unique_ptr{ dockpn }); - } + //The fields are allowed to have a same name. E.g. + //place.div("A "); + //place.modify("A", ""); Here the same name B must be allowed, otherwise it throws std::invalid_argument. - division * next = nullptr; - for (int i = static_cast(adjusted_children.size()) - 1; i >= 0; --i) - { - adjusted_children[i]->div_next = next; - next = adjusted_children[i].get(); - } + bool allow_same_name = false; + if (!ignore_duplicate.empty()) + { + auto f = attached_field->attached->div_owner; + while (f) + { + if (f->name == ignore_duplicate) + { + allow_same_name = true; + break; + } - children.swap(adjusted_children); + f = f->div_owner; + } + } + + if (!allow_same_name) + throw std::invalid_argument("redefined field name"); + } } + + token unmatch = token::width; + switch (div_type) + { + case token::eof: // "horizontal" div + case token::vert: // "vertical" div + if (token::eof == div_type) + unmatch = token::height; + + for (auto& ch : children) + if (ch->weigth_type == unmatch) + throw std::invalid_argument("unmatch vertical-height/horizontal-width between division '" + + name + "' and children division '" + ch->name); + + div.reset(new div_arrange(token::vert == div_type, std::move(name), std::move(arrange))); + break; + case token::grid: + { + std::unique_ptr p(new div_grid(std::move(name), std::move(arrange), std::move(collapses))); + + if (array.size()) + p->dimension.first = array[0].integer(); + + if (array.size() > 1) + p->dimension.second = array[1].integer(); + + if (0 == p->dimension.first) + p->dimension.first = 1; + + if (0 == p->dimension.second) + p->dimension.second = 1; + + p->revise_collapses(); + div = std::move(p); + } + break; + case token::dock: + div.reset(new div_dock(std::move(name), this)); + break; + case token::switchable: + div.reset(new div_switchable(std::move(name), this)); + break; + default: + throw std::invalid_argument("invalid division type."); + } + div->weigth_type = weight_type; + + //Requirements for min/max + //1, min and max != negative + //2, max >= min + if (min_px.is_negative()) min_px.reset(); + if (max_px.is_negative()) max_px.reset(); + if ((!min_px.empty()) && (!max_px.empty()) && (min_px.get_value(100) > max_px.get_value(100))) + { + min_px.reset(); + max_px.reset(); + } + + if (!min_px.empty()) + div->min_px = min_px; + + if (!max_px.empty()) + div->max_px = max_px; + + if ((!min_px.empty()) && (!weight.empty()) && (weight.get_value(100) < min_px.get_value(100))) + weight.reset(); + + if ((!max_px.empty()) && (!weight.empty()) && (weight.get_value(100) > max_px.get_value(100))) + weight.reset(); + + if (!weight.empty()) + div->weight = weight; + + div->gap = std::move(gap); + + //attach the field to the division + div->field = attached_field; + if (attached_field) + { + //Replaces the previous div with the new div which is allowed to have a same name. + + //Detaches the field from the previous div. + if (attached_field->attached) + attached_field->attached->field = nullptr; + + //Attaches new div + attached_field->attached = div.get(); + } + + if (children.size()) + { + if (division::kind::splitter == children.back()->kind_of_division) + { + children.pop_back(); + if (children.size()) + children.back()->div_next = nullptr; + } + + for (auto& child : children) + { + child->div_owner = div.get(); + if (division::kind::splitter == child->kind_of_division) + dynamic_cast(*child).direction(div_type != token::vert); + } + + if (token::dock == div_type) + { + //adjust these children for dock division + std::vector> adjusted_children; + for (auto& child : children) + { + auto dockpn = new div_dockpane(std::move(child->name), this, child->dir); + dockpn->div_owner = child->div_owner; + dockpn->weight = child->weight; + adjusted_children.emplace_back(std::unique_ptr{ dockpn }); + } + + division* next = nullptr; + for (int i = static_cast(adjusted_children.size()) - 1; i >= 0; --i) + { + adjusted_children[i]->div_next = next; + next = adjusted_children[i].get(); + } + + children.swap(adjusted_children); + } + } + + div->children.swap(children); + div->margin = std::move(margin); + div->dir = div_dir; + + div->display = !undisplayed; + div->visible = !(undisplayed || invisible); + div->fit = fit; + div->fit_parameters = std::move(fit_parameters); + } + catch (place::error& e) { throw; } + catch ( error& e) { throw; } + catch (place_parts::tokenizer::error& e) + { + throw error(e.what(), name, e.pos); + } + catch (std::invalid_argument& e) + { + throw error(e.what(), name, tknizer.pos()); + } + catch (std::exception& e) + { + throw error(std::string{"unexpected error: "}+e.what(), name, tknizer.pos()); + } + catch (...) + { + throw error("unknow error", name, tknizer.pos()); } - - div->children.swap(children); - div->margin = std::move(margin); - div->dir = div_dir; - - div->display = !undisplayed; - div->visible = !(undisplayed || invisible); - div->fit = fit; - div->fit_parameters = std::move(fit_parameters); - return div; } @@ -3265,16 +3289,20 @@ namespace nana void place::div(std::string div_text) { - place_parts::tokenizer tknizer(div_text.c_str()); - impl_->disconnect(); - auto div = impl_->scan_div(tknizer, true); try { + place_parts::tokenizer tknizer(div_text.c_str()); + impl_->disconnect(); + auto div = impl_->scan_div(tknizer, true); impl_->connect(div.get()); //throws if there is a redefined name of field. impl_->root_division.reset(); //clear attachments div-fields impl_->root_division.swap(div); impl_->div_text.swap(div_text); } + catch (place::implement::error & e) + { + throw place::error("failed to set div('"+div_text+"'): " + e.what(), *this, e.field, e.pos); + } catch (...) // tokenizer error { //redefined a name of field @@ -3295,19 +3323,15 @@ namespace nana void place::modify(const char* name, const char* div_text) { if (nullptr == div_text) - throw error("nana::place.modify(): invalid div-text (nullptr)", *this); + throw error("modify(): invalid div-text (=nullptr)", *this); if (! valid_field_name(name) ) - throw badname("nana::place.modify()", *this, name); + throw badname("modify()", *this, name); auto div_ptr = impl_->search_div_name(impl_->root_division.get(), name); if (!div_ptr) - { - std::string what = "nana::place.modify(): field '"; - what += name; - what += "' was not found."; - throw error(what, *this, name); - } + throw error("modify(): field was not found", *this, name); + std::unique_ptr* replaced = nullptr; @@ -3361,17 +3385,22 @@ namespace nana } } } - catch (...) /// todo throw error !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + catch (std::exception&e) { replaced->swap(impl_->tmp_replaced); - throw; + throw error( std::string("modify()")+e.what(), *this, name); + } + catch (...) + { + replaced->swap(impl_->tmp_replaced); + throw error("modify() unknonw error", *this, name); } } place::field_reference place::field(const char* name) { if (!valid_field_name(name)) - throw badname("nana::place.field()", *this, name); + throw badname("field()", *this, name); //get the field with the specified name. If no such field with specified name //then create one. @@ -3387,8 +3416,7 @@ namespace nana if (div) { if (div->field && (div->field != p)) - throw error(std::string("nana::place.field(): unexpected error, the division attaches an unexpected field: ") + name, - *this, name); + throw error("field(): the division attaches an unexpected field", *this, name); div->field = p; p->attached = div; @@ -3466,7 +3494,7 @@ namespace nana void place::field_visible(const char* name, bool vsb) { if (!valid_field_name(name)) - throw badname("set nana::place.field_visible()", *this, name); + throw badname("field_visible()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); if (div) @@ -3479,7 +3507,7 @@ namespace nana bool place::field_visible(const char* name) const { if (!valid_field_name(name)) - throw badname("get nana::place.field_visible()", *this, name); + throw badname("field_visible()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); return (div && div->visible); @@ -3488,7 +3516,7 @@ namespace nana void place::field_display(const char* name, bool dsp) { if (!valid_field_name(name)) - throw badname("set nana::place.field_display()", *this, name); + throw badname("field_display()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); if (div) @@ -3502,7 +3530,7 @@ namespace nana bool place::field_display(const char* name) const { if (!valid_field_name(name)) - throw badname("get nana::place.field_display()", *this, name); + throw badname("field_display()", *this, name); auto div = impl_->search_div_name(impl_->root_division.get(), name); return (div && div->display); @@ -3540,7 +3568,7 @@ namespace nana place& place::dock(const std::string& name, std::string factory_name, std::function(window)> factory) { if (!valid_field_name(name.data())) - throw badname("get nana::place.field_display()", *this, name.data()); + throw badname("dock()", *this, name.data()); auto & dock_ptr = impl_->docks[name]; if (!dock_ptr) @@ -3550,7 +3578,7 @@ namespace nana if (!factory_name.empty()) { if (impl_->dock_factoris.find(factory_name) != impl_->dock_factoris.end()) - throw std::invalid_argument("nana::place - the specified factory name(" + factory_name + ") already exists"); + throw error("dock() - the specified factory name(" + factory_name + ") already exists", *this, name); impl_->dock_factoris[factory_name] = dock_ptr; dock_ptr->factories[factory_name] = std::move(factory); @@ -3586,7 +3614,7 @@ namespace nana { auto i = impl_->dock_factoris.find(factory); if (i == impl_->dock_factoris.end()) - throw std::invalid_argument("invalid factory name(" + factory + ") of dockpane"); + throw std::invalid_argument("nana::place::dock_create - invalid factory name(" + factory + ") of dockpane"); auto dock_ptr = i->second; if (dock_ptr->attached) @@ -3607,9 +3635,24 @@ namespace nana return nullptr; } - //end class place + + place::error::error(const std::string& what, + const place& plc, + std::string field, + std::string::size_type pos) - //class place::error + : std::invalid_argument{ "nana::place error " + what + + " from widget '" + API::window_caption(plc.window_handle()).substr(0,80) + + "' in fleld '" + field + + (pos == std::string::npos ? "' " : "' at at position " + std::to_string(pos)) + + " in div_text:\n" + plc.div() }, + base_what{ what }, + owner_caption{ API::window_caption(plc.window_handle()).substr(0,80) }, + field{ field }, + div_text{ plc.div() }, + pos{ pos } + {} + //end class place }//end namespace nana