1 /*
2 	Copyright 2006-2019 The QElectroTech Team
3 	This file is part of QElectroTech.
4 
5 	QElectroTech is free software: you can redistribute it and/or modify
6 	it under the terms of the GNU General Public License as published by
7 	the Free Software Foundation, either version 2 of the License, or
8 	(at your option) any later version.
9 
10 	QElectroTech is distributed in the hope that it will be useful,
11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 	GNU General Public License for more details.
14 
15 	You should have received a copy of the GNU General Public License
16 	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "templatelogomanager.h"
19 #include "titleblocktemplate.h"
20 #include "qeticons.h"
21 
22 #include <QStandardPaths>
23 
24 /**
25 	Constructor
26 	@param managed_template Title block template this widget manages logos for.
27 	@param parent Parent QWidget.
28 */
TitleBlockTemplateLogoManager(TitleBlockTemplate * managed_template,QWidget * parent)29 TitleBlockTemplateLogoManager::TitleBlockTemplateLogoManager(TitleBlockTemplate *managed_template, QWidget *parent) :
30 	QWidget(parent),
31 	managed_template_(managed_template)
32 {
33 	initWidgets();
34 	fillView();
35 }
36 
37 /**
38 	Destructor
39 */
~TitleBlockTemplateLogoManager()40 TitleBlockTemplateLogoManager::~TitleBlockTemplateLogoManager() {
41 }
42 
43 /**
44 	@return the name of the currently selected logo, or a null QString if none
45 	is selected.
46 */
currentLogo() const47 QString TitleBlockTemplateLogoManager::currentLogo() const {
48 	if (!managed_template_) return QString();
49 
50 	QListWidgetItem *current_item = logos_view_ -> currentItem();
51 	if (!current_item) return QString();
52 
53 	return(current_item -> text());
54 }
55 
56 /**
57 	@return Whether this logo manager should allow logo edition
58 	(renaming, addition, deletion).
59 */
isReadOnly() const60 bool TitleBlockTemplateLogoManager::isReadOnly() const {
61 	return(read_only_);
62 }
63 
64 /**
65 	Emit the logosChanged() signal.
66 */
emitLogosChangedSignal()67 void TitleBlockTemplateLogoManager::emitLogosChangedSignal() {
68 	emit(logosChanged(const_cast<const TitleBlockTemplate *>(managed_template_)));
69 }
70 
71 /**
72 	Initialize widgets composing the Logo manager
73 */
initWidgets()74 void TitleBlockTemplateLogoManager::initWidgets() {
75 	open_dialog_dir_ = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
76 
77 	setWindowTitle(tr("Gestionnaire de logos"));
78 	setWindowIcon(QET::Icons::InsertImage);
79 	setWindowFlags(Qt::Dialog);
80 	logos_label_ = new QLabel(tr("Logos embarqués dans ce modèle :"));
81 	logos_view_ = new QListWidget();
82 	logos_view_ -> setViewMode(QListView::IconMode);
83 	logos_view_ -> setGridSize(iconsize() * 1.4);
84 	logos_view_ -> setMinimumSize(iconsize() * 2.9);
85 	logos_view_ -> setIconSize(iconsize());
86 	logos_view_ -> setWrapping(true);
87 	logos_view_ -> setMovement(QListView::Static);
88 	logos_view_ -> setResizeMode(QListView::Adjust);
89 	add_button_ = new QPushButton(QET::Icons::Add, tr("Ajouter un logo"));
90 	export_button_ = new QPushButton(QET::Icons::DocumentExport, tr("Exporter ce logo"));
91 	delete_button_ = new QPushButton(QET::Icons::Remove, tr("Supprimer ce logo"));
92 	logo_box_ = new QGroupBox(tr("Propriétés"));
93 	logo_name_label_ = new QLabel(tr("Nom :"));
94 	logo_name_ = new QLineEdit();
95 	rename_button_ = new QPushButton(QET::Icons::EditRename, tr("Renommer"));
96 	logo_type_ = new QLabel(tr("Type :"));
97 	buttons_ = new QDialogButtonBox(QDialogButtonBox::Ok);
98 
99 	hlayout1_ = new QHBoxLayout();
100 	hlayout1_ -> addWidget(logo_name_label_);
101 	hlayout1_ -> addWidget(logo_name_);
102 	hlayout1_ -> addWidget(rename_button_);
103 
104 	hlayout0_ = new QHBoxLayout();
105 	hlayout0_ -> addWidget(export_button_);
106 	hlayout0_ -> addWidget(delete_button_);
107 
108 	vlayout1_ = new QVBoxLayout();
109 	vlayout1_ -> addLayout(hlayout1_);
110 	vlayout1_ -> addWidget(logo_type_);
111 	logo_box_ -> setLayout(vlayout1_);
112 
113 	vlayout0_ = new QVBoxLayout();
114 	vlayout0_ -> addWidget(logos_label_);
115 	vlayout0_ -> addWidget(logos_view_);
116 	vlayout0_ -> addWidget(add_button_);
117 	vlayout0_ -> addLayout(hlayout0_);
118 	vlayout0_ -> addWidget(logo_box_);
119 	setLayout(vlayout0_);
120 
121 	connect(
122 		logos_view_,
123 		SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
124 		this,
125 		SLOT(updateLogoInformations(QListWidgetItem *, QListWidgetItem *))
126 	);
127 	connect(add_button_, SIGNAL(released()), this, SLOT(addLogo()));
128 	connect(export_button_, SIGNAL(released()), this, SLOT(exportLogo()));
129 	connect(delete_button_, SIGNAL(released()), this, SLOT(removeLogo()));
130 	connect(rename_button_, SIGNAL(released()), this, SLOT(renameLogo()));
131 }
132 
133 /**
134 	Update the logos display.
135 */
fillView()136 void TitleBlockTemplateLogoManager::fillView() {
137 	if (!managed_template_) return;
138 	logos_view_ -> clear();
139 
140 	foreach (QString logo_name, managed_template_ -> logos()) {
141 		QIcon current_icon;
142 		QPixmap current_logo = managed_template_ -> bitmapLogo(logo_name);
143 		if (!current_logo.isNull()) {
144 			current_icon = QIcon(current_logo);
145 		} else {
146 			QSvgRenderer *svg_logo = managed_template_ -> vectorLogo(logo_name);
147 			if (svg_logo) {
148 				QPixmap *svg_pixmap = new QPixmap(iconsize());
149 				svg_pixmap -> fill();
150 				QPainter p;
151 				p.begin(svg_pixmap);
152 				svg_logo -> render(&p);
153 				p.end();
154 				current_icon = QIcon(*svg_pixmap);
155 			}
156 		}
157 		QListWidgetItem *qlwi = new QListWidgetItem(current_icon, logo_name);
158 		qlwi -> setTextAlignment(Qt::AlignBottom | Qt::AlignHCenter);
159 		logos_view_ -> insertItem(0, qlwi);
160 	}
161 
162 	QListWidgetItem *current_item = logos_view_ -> currentItem();
163 	updateLogoInformations(current_item, nullptr);
164 }
165 
166 /**
167 	@return the icon size to display the logos embedded within the managed
168 	template.
169 */
iconsize() const170 QSize TitleBlockTemplateLogoManager::iconsize() const {
171 	return(QSize(80, 80));
172 }
173 
174 /**
175 	When adding a logo, it may occur its name is already used by another
176 	pre-existing logo. This method asks users whether they want to erase the
177 	existing logo, change the initial name or simply cancel the operation.
178 	@param initial_name Initial name of the logo to be added
179 	@return Either a null QString if the user cancelled the operation, or the
180 	name to be used when adding the logo.
181 */
confirmLogoName(const QString & initial_name)182 QString TitleBlockTemplateLogoManager::confirmLogoName(const QString &initial_name) {
183 	QString name = initial_name;
184 	QDialog *rename_dialog = nullptr;
185 	QLabel *rd_label = nullptr;
186 	QLineEdit *rd_input = nullptr;
187 	while (managed_template_ -> logos().contains(name)) {
188 		if (!rename_dialog) {
189 			rename_dialog = new QDialog(this);
190 			rename_dialog -> setWindowTitle(tr("Logo déjà existant"));
191 
192 			rd_label = new QLabel();
193 			rd_label -> setWordWrap(true);
194 			rd_input = new QLineEdit();
195 			QDialogButtonBox *rd_buttons = new QDialogButtonBox();
196 			QPushButton *replace_button = rd_buttons -> addButton(tr("Remplacer"), QDialogButtonBox::YesRole);
197 			QPushButton *rename_button  = rd_buttons -> addButton(tr("Renommer"),  QDialogButtonBox::NoRole);
198 			QPushButton *cancel_button  = rd_buttons -> addButton(QDialogButtonBox::Cancel);
199 
200 			QVBoxLayout *rd_vlayout0 = new QVBoxLayout();
201 			rd_vlayout0 -> addWidget(rd_label);
202 			rd_vlayout0 -> addWidget(rd_input);
203 			rd_vlayout0 -> addWidget(rd_buttons);
204 			rename_dialog -> setLayout(rd_vlayout0);
205 
206 			QSignalMapper *signal_mapper = new QSignalMapper(rename_dialog);
207 			signal_mapper -> setMapping(replace_button, QDialogButtonBox::YesRole);
208 			signal_mapper -> setMapping(rename_button,  QDialogButtonBox::NoRole);
209 			signal_mapper -> setMapping(cancel_button,  QDialogButtonBox::RejectRole);
210 			connect(replace_button, SIGNAL(clicked()), signal_mapper, SLOT(map()));
211 			connect(rename_button,  SIGNAL(clicked()), signal_mapper, SLOT(map()));
212 			connect(cancel_button,  SIGNAL(clicked()), signal_mapper, SLOT(map()));
213 			connect(signal_mapper, SIGNAL(mapped(int)), rename_dialog, SLOT(done(int)));
214 		}
215 		rd_label -> setText(
216 			QString(tr(
217 				"Il existe déjà un logo portant le nom \"%1\" au sein de "
218 				"ce modèle de cartouche. Voulez-vous le remplacer ou "
219 				"préférez-vous spécifier un autre nom pour ce nouveau "
220 				"logo ?"
221 			)).arg(name)
222 		);
223 		rd_input -> setText(name);
224 		int answer = rename_dialog -> exec();
225 		if (answer == QDialogButtonBox::YesRole) {
226 			// we can use the initial name
227 			break;
228 		} else if (answer == QDialogButtonBox::NoRole) {
229 			// the user provided another name
230 			name = rd_input -> text();
231 			/// TODO prevent the user from entering an empty name
232 		} else {
233 			// the user cancelled the operation
234 			return(QString());
235 		}
236 	};
237 	return(name);
238 }
239 
240 /**
241 	Update the displayed informations relative to the currently selected logo.
242 	@param current  Newly selected logo item
243 	@param previous Previously selected logo item
244 */
updateLogoInformations(QListWidgetItem * current,QListWidgetItem * previous)245 void TitleBlockTemplateLogoManager::updateLogoInformations(QListWidgetItem *current, QListWidgetItem *previous) {
246 	Q_UNUSED(previous);
247 	if (current) {
248 		QString logo_name = current -> text();
249 		logo_name_ -> setText(logo_name);
250 		if (managed_template_) {
251 			QString logo_type = managed_template_ -> logoType(logo_name);
252 			logo_type_ -> setText(tr("Type : %1").arg(logo_type));
253 		}
254 	} else {
255 		logo_name_ -> setText(QString());
256 		logo_type_ -> setText(tr("Type :"));
257 	}
258 }
259 
260 /**
261 	Ask the user for a filepath, and add it as a new logo in the managed
262 	template.
263 */
addLogo()264 void TitleBlockTemplateLogoManager::addLogo() {
265 	if (!managed_template_) return;
266 
267 	QString filepath = QFileDialog::getOpenFileName(
268 		this,
269 		tr("Choisir une image / un logo"),
270 		open_dialog_dir_.absolutePath(),
271 		tr("Images vectorielles (*.svg);;Images bitmap (*.png *.jpg *.jpeg *.gif *.bmp *.xpm);;Tous les fichiers (*)")
272 	);
273 	if (filepath.isEmpty()) return;
274 
275 	// that filepath needs to point to a valid, readable file
276 	QFileInfo filepath_info(filepath);
277 	if (!filepath_info.exists() || !filepath_info.isReadable()) {
278 		QMessageBox::critical(this, tr("Erreur"), tr("Impossible d'ouvrir le fichier spécifié"));
279 		return;
280 	}
281 
282 	// ensure we can use the file name to add the logo
283 	QString logo_name = confirmLogoName(filepath_info.fileName());
284 	if (logo_name.isNull()) return;
285 
286 	open_dialog_dir_ = QDir(filepath);
287 	if (managed_template_ -> addLogoFromFile(filepath, logo_name)) {
288 		fillView();
289 		emitLogosChangedSignal();
290 	}
291 }
292 
293 /**
294 	Export the currently selected logo
295 */
exportLogo()296 void TitleBlockTemplateLogoManager::exportLogo() {
297 	QString current_logo = currentLogo();
298 	if (current_logo.isNull()) return;
299 
300 	QString filepath = QFileDialog::getSaveFileName(
301 		this,
302 		tr("Choisir un fichier pour exporter ce logo"),
303 		open_dialog_dir_.absolutePath() + "/" + current_logo,
304 		tr("Tous les fichiers (*);;Images vectorielles (*.svg);;Images bitmap (*.png *.jpg *.jpeg *.gif *.bmp *.xpm)")
305 	);
306 	if (filepath.isEmpty()) return;
307 
308 	bool save_logo = managed_template_ -> saveLogoToFile(current_logo, filepath);
309 	if (!save_logo) {
310 		QMessageBox::critical(this, tr("Erreur"), QString(tr("Impossible d'exporter vers le fichier spécifié")));
311 	} else {
312 		open_dialog_dir_ = QDir(filepath);
313 	}
314 }
315 
316 /**
317 	Delete the currently selected logo.
318 */
removeLogo()319 void TitleBlockTemplateLogoManager::removeLogo() {
320 	QString current_logo = currentLogo();
321 	if (current_logo.isNull()) return;
322 
323 	if (managed_template_ -> removeLogo(current_logo)) {
324 		fillView();
325 		emitLogosChangedSignal();
326 	}
327 }
328 
329 /**
330 	Rename currently selected logo.
331 */
renameLogo()332 void TitleBlockTemplateLogoManager::renameLogo() {
333 	QString current_logo = currentLogo();
334 	if (current_logo.isNull()) return;
335 
336 	QString entered_name = logo_name_ -> text();
337 	QString warning_title = tr("Renommer un logo");
338 	if (entered_name == current_logo) {
339 		QMessageBox::warning(
340 			this,
341 			warning_title,
342 			tr("Vous devez saisir un nouveau nom.")
343 		);
344 		return;
345 	}
346 
347 	if (entered_name.trimmed().isEmpty()) {
348 		QMessageBox::warning(
349 			this,
350 			warning_title,
351 			tr("Le nouveau nom ne peut pas être vide.")
352 		);
353 		return;
354 	}
355 
356 	if (managed_template_ -> logos().contains(entered_name)) {
357 		QMessageBox::warning(
358 			this,
359 			warning_title,
360 			tr("Le nom saisi est déjà utilisé par un autre logo.")
361 		);
362 		return;
363 	}
364 
365 	if (managed_template_ -> renameLogo(current_logo, entered_name)) {
366 		fillView();
367 		emitLogosChangedSignal();
368 	}
369 }
370 
371 /**
372 	@param read_only Whether this logo manager should allow logo edition
373 	(renaming, addition, deletion)
374 */
setReadOnly(bool read_only)375 void TitleBlockTemplateLogoManager::setReadOnly(bool read_only) {
376 	if (read_only_ == read_only) return;
377 	read_only_ = read_only;
378 
379 	add_button_ -> setEnabled(!read_only_);
380 	delete_button_ -> setEnabled(!read_only_);
381 	rename_button_ -> setEnabled(!read_only_);
382 	logo_name_ -> setReadOnly(read_only_);
383 }
384