Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
selection-describer.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Inkscape::SelectionDescriber - shows messages describing selection
4 *
5 * Authors:
6 * MenTaLguY <mental@rydia.net>
7 * bulia byak <buliabyak@users.sf.net>
8 * Abhishek Sharma
9 * Jon A. Cruz <jon@joncruz.org>
10 *
11 * Copyright (C) 2004-2006 Authors
12 *
13 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
14 */
15
16#include <memory>
17#include <set>
18#include <utility>
19
20#include <glibmm/i18n.h>
21
22#include "selection-describer.h"
23
24#include "layer-manager.h"
25#include "selection.h"
26#include "desktop.h"
27
28#include "object/sp-flowtext.h"
29#include "object/sp-image.h"
30#include "object/sp-offset.h"
31#include "object/sp-path.h"
32#include "object/sp-symbol.h"
33#include "object/sp-textpath.h"
34#include "object/sp-use.h"
35
36#include "xml/quote.h"
37
38// Returns a list of terms for the items to be used in the statusbar
39char* collect_terms (const std::vector<SPItem*> &items)
40{
41 std::set<Glib::ustring> check;
42 std::stringstream ss;
43 bool first = true;
44
45 for (auto item : items) {
46 if (item && item->displayName()) {
47 Glib::ustring term(item->displayName());
48 if (term != "" && (check.insert(term).second)) {
49 ss << (first ? "" : ", ") << "<b>" << term.raw() << "</b>";
50 first = false;
51 }
52 }
53 }
54 return g_strdup(ss.str().c_str());
55}
56
57// Returns the number of terms in the list
58static int count_terms (const std::vector<SPItem*> &items)
59{
60 std::set<Glib::ustring> check;
61 int count=0;
62 for (auto item : items) {
63 if (item && item->displayName()) {
64 Glib::ustring term(item->displayName());
65 if (term != "" && (check.insert(term).second)) {
66 count++;
67 }
68 }
69 }
70 return count;
71}
72
73// Returns the number of filtered items in the list
74static int count_filtered (const std::vector<SPItem*> &items)
75{
76 int count=0;
77 for (auto item : items) {
78 if (item) {
79 count += item->isFiltered();
80 }
81 }
82 return count;
83}
84
85
86namespace Inkscape {
87
88SelectionDescriber::SelectionDescriber(Inkscape::Selection *selection, MessageStack &stack, char *when_selected, char *when_nothing)
89 : _context{stack}
90 , _when_selected{when_selected}
91 , _when_nothing{when_nothing}
92{
94 sigc::mem_fun(*this, &SelectionDescriber::updateMessage));
95 updateMessage(selection);
96}
97
99
101 std::vector<SPItem*> items(selection->items().begin(), selection->items().end());
102
103 if (items.empty()) { // no items
105 } else {
106 SPItem *item = items[0];
107 g_assert(item != nullptr);
108 SPObject *layer = selection->desktop()->layerManager().layerForObject(item);
109 SPObject *root = selection->desktop()->layerManager().currentRoot();
110
111 // Layer name
112 gchar *layer_name;
113 if (layer == root) {
114 layer_name = g_strdup(_("root"));
115 } else if(!layer) {
116 layer_name = g_strdup(_("none"));
117 } else {
118 char const *layer_label;
119 bool is_label = false;
120 if (layer->label()) {
121 layer_label = layer->label();
122 is_label = true;
123 } else {
124 layer_label = layer->defaultLabel();
125 }
126 char *quoted_layer_label = xml_quote_strdup(layer_label);
127 if (is_label) {
128 layer_name = g_strdup_printf(_("layer <b>%s</b>"), quoted_layer_label);
129 } else {
130 layer_name = g_strdup_printf(_("layer <b><i>%s</i></b>"), quoted_layer_label);
131 }
132 g_free(quoted_layer_label);
133 }
134
135 // Parent name
137 if (!parent) { // fix selector * to "svg:svg"
138 return;
139 }
140 gchar const *parent_label = parent->getId();
141 gchar *parent_name = nullptr;
142 if (parent_label) {
143 char *quoted_parent_label = xml_quote_strdup(parent_label);
144 parent_name = g_strdup_printf(_("<i>%s</i>"), quoted_parent_label);
145 g_free(quoted_parent_label);
146 }
147
148 gchar *in_phrase;
149 guint num_layers = selection->numberOfLayers();
150 guint num_parents = selection->numberOfParents();
151 if (num_layers == 1) {
152 if (num_parents == 1) {
153 if (layer == parent)
154 in_phrase = g_strdup_printf(_(" in %s"), layer_name);
155 else if (!layer)
156 in_phrase = g_strdup_printf("%s", _(" hidden in definitions"));
157 else if (parent_name)
158 in_phrase = g_strdup_printf(_(" in group %s (%s)"), parent_name, layer_name);
159 else
160 in_phrase = g_strdup_printf(_(" in unnamed group (%s)"), layer_name);
161 } else {
162 in_phrase = g_strdup_printf(ngettext(" in <b>%i</b> parent (%s)", " in <b>%i</b> parents (%s)", num_parents), num_parents, layer_name);
163 }
164 } else {
165 in_phrase = g_strdup_printf(ngettext(" in <b>%i</b> layer", " in <b>%i</b> layers", num_layers), num_layers);
166 }
167 g_free (layer_name);
168 g_free (parent_name);
169
170 if (items.size()==1) { // one item
171 char *item_desc = item->detailedDescription();
172
173 bool isUse = is<SPUse>(item);
174 if (isUse && is<SPSymbol>(item->firstChild())) {
175 _context.setF(Inkscape::NORMAL_MESSAGE, "%s%s. %s. %s.",
176 item_desc, in_phrase,
177 _("Convert symbol to group to edit"), _when_selected);
178 } else if (is<SPSymbol>(item)) {
180 item_desc, in_phrase,
181 _("Remove from symbols tray to edit symbol"));
182 } else {
183 SPOffset *offset = isUse ? nullptr : cast<SPOffset>(item);
184 if (isUse || (offset && offset->sourceHref)) {
185 _context.setF(Inkscape::NORMAL_MESSAGE, "%s%s. %s. %s.",
186 item_desc, in_phrase,
187 _("Use <b>Shift+D</b> to look up original"), _when_selected);
188 } else {
189 auto text = cast<SPText>(item);
190 if (text && text->firstChild() && is<SPText>(text->firstChild())) {
191 _context.setF(Inkscape::NORMAL_MESSAGE, "%s%s. %s. %s.",
192 item_desc, in_phrase,
193 _("Use <b>Shift+D</b> to look up path"), _when_selected);
194 } else {
195 auto flowtext = cast<SPFlowtext>(item);
196 if (flowtext && !flowtext->has_internal_frame()) {
197 _context.setF(Inkscape::NORMAL_MESSAGE, "%s%s. %s. %s.",
198 item_desc, in_phrase,
199 _("Use <b>Shift+D</b> to look up frame"), _when_selected);
200 } else {
202 item_desc, in_phrase, _when_selected);
203 }
204 }
205 }
206 }
207
208 g_free(item_desc);
209 } else { // multiple items
210 int objcount = items.size();
211 char *terms = collect_terms (items);
212 int n_terms = count_terms(items);
213
214 gchar *objects_str = g_strdup_printf(ngettext(
215 "<b>%1$i</b> objects selected of type %2$s",
216 "<b>%1$i</b> objects selected of types %2$s", n_terms),
217 objcount, terms);
218
219 g_free(terms);
220
221 // indicate all, some, or none filtered
222 gchar *filt_str = nullptr;
223 int n_filt = count_filtered(items); //all filtered
224 if (n_filt) {
225 filt_str = g_strdup_printf(ngettext("; <i>%d filtered object</i> ",
226 "; <i>%d filtered objects</i> ", n_filt), n_filt);
227 } else {
228 filt_str = g_strdup("");
229 }
230
231 _context.setF(Inkscape::NORMAL_MESSAGE, "%s%s%s. %s.", objects_str, filt_str, in_phrase, _when_selected);
232 if (objects_str) {
233 g_free(objects_str);
234 objects_str = nullptr;
235 }
236 if (filt_str) {
237 g_free(filt_str);
238 filt_str = nullptr;
239 }
240 }
241
242 g_free(in_phrase);
243 }
244}
245
246}
247
248/*
249 Local Variables:
250 mode:c++
251 c-file-style:"stroustrup"
252 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
253 indent-tabs-mode:nil
254 fill-column:99
255 End:
256*/
257// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
SPObject * layerForObject(SPObject *object)
Return layer that contains object.
SPGroup * currentRoot() const
Returns current root (=bottom) layer.
void set(MessageType type, char const *message)
pushes a message on the stack, replacing our old message
void setF(MessageType type, char const *format,...) G_GNUC_PRINTF(3
pushes a message on the stack using prinf-style formatting, and replacing our old message
A class which holds a stack of displayed messages.
SPDesktop * desktop()
Returns the desktop the selection is bound to.
Definition object-set.h:365
SPItemRange items()
Returns a range of selected SPItems.
Definition object-set.h:230
void updateMessage(Inkscape::Selection *selection)
sigc::scoped_connection _selection_changed_connection
SelectionDescriber(Inkscape::Selection *selection, MessageStack &stack, char *when_selected, char *when_nothing)
The set of selected SPObjects for a given document and layer model.
Definition selection.h:80
size_t numberOfLayers()
Returns the number of layers in which there are selected objects.
size_t numberOfParents()
Returns the number of parents to which the selected objects belong.
sigc::connection connectChanged(sigc::slot< void(Selection *)> slot)
Connects a slot to be notified of selection changes.
Definition selection.h:179
Inkscape::LayerManager & layerManager()
Definition desktop.h:287
Base class for visual SVG elements.
Definition sp-item.h:109
bool isFiltered() const
Returns true if the item is filtered, false otherwise.
Definition sp-item.cpp:1234
virtual const char * displayName() const
The item's type name as a translated human string.
Definition sp-item.cpp:1193
char * detailedDescription() const
Returns a string suitable for status bar, formatted in pango markup language.
Definition sp-item.cpp:1201
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
char const * label() const
Gets the author-visible label property for the object or a default if no label is defined.
SPObject * firstChild()
Definition sp-object.h:315
char const * getId() const
Returns the objects current ID string.
char const * defaultLabel() const
Returns a default label property for this object.
SPObject * parent
Definition sp-object.h:189
SPOffset class.
Definition sp-offset.h:50
RootCluster root
Editable view implementation.
static char const *const parent
Definition dir-util.cpp:70
SPItem * item
double offset
Helper class to stream background task notifications as a series of messages.
@ NORMAL_MESSAGE
Definition message.h:26
char * xml_quote_strdup(char const *src)
Definition quote.cpp:43
TODO: insert short description here.
GList * items
static int count_filtered(const std::vector< SPItem * > &items)
char * collect_terms(const std::vector< SPItem * > &items)
static int count_terms(const std::vector< SPItem * > &items)
TODO: insert short description here.
SVG <image> implementation.
TODO: insert short description here.
Gtk::Stack & stack