1 /*
2 # PostgreSQL Database Modeler (pgModeler)
3 #
4 # Copyright 2006-2020 - Raphael Araújo e Silva <raphael@pgmodeler.io>
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation version 3.
9 #
10 # This program 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 # The complete text of GPLv3 is at LICENSE file on source code root directory.
16 # Also, you can get the complete GNU General Public License at <http://www.gnu.org/licenses/>
17 */
18 
19 #include "fileselectorwidget.h"
20 #include "pgmodeleruins.h"
21 
FileSelectorWidget(QWidget * parent)22 FileSelectorWidget::FileSelectorWidget(QWidget *parent) : QWidget(parent)
23 {
24 	setupUi(this);
25 	allow_filename_input = read_only = false;
26 
27 	file_dlg.setWindowIcon(QPixmap(PgModelerUiNs::getIconPath("pgsqlModeler48x48")));
28 
29 	filename_edt->setReadOnly(true);
30 	filename_edt->installEventFilter(this);
31 
32 	warn_ico_lbl = new QLabel(this);
33 	warn_ico_lbl->setVisible(false);
34 	warn_ico_lbl->setMinimumSize(filename_edt->height(), filename_edt->height());
35 	warn_ico_lbl->setMaximumSize(warn_ico_lbl->minimumSize());
36 	warn_ico_lbl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
37 	warn_ico_lbl->setScaledContents(true);
38 	warn_ico_lbl->setPixmap(QPixmap(PgModelerUiNs::getIconPath("msgbox_alerta")));
39 	warn_ico_lbl->setToolTip(tr("No such file or directory!"));
40 
41 	connect(sel_file_tb, SIGNAL(clicked(bool)), this, SLOT(openFileDialog()));
42 	connect(rem_file_tb, SIGNAL(clicked(bool)), this, SLOT(clearSelector()));
43 	connect(filename_edt, &QLineEdit::textChanged, [&](const QString &text){
44 		rem_file_tb->setEnabled(!text.isEmpty());
45 		validateSelectedFile();
46 		emit s_selectorChanged(!text.isEmpty());
47 	});
48 }
49 
eventFilter(QObject * obj,QEvent * evnt)50 bool FileSelectorWidget::eventFilter(QObject *obj, QEvent *evnt)
51 {
52 	if(isEnabled() && evnt->type() == QEvent::FocusIn &&
53 		 QApplication::mouseButtons() == Qt::LeftButton && obj == filename_edt)
54 	{
55 		QFocusEvent *focus_evnt = dynamic_cast<QFocusEvent *>(evnt);
56 
57 		if(!allow_filename_input && !read_only && focus_evnt->reason() == Qt::MouseFocusReason)
58 		{
59 			openFileDialog();
60 			return true;
61 		}
62 	}
63 
64 	return QWidget::eventFilter(obj, evnt);
65 }
66 
resizeEvent(QResizeEvent *)67 void FileSelectorWidget::resizeEvent(QResizeEvent *)
68 {
69 	warn_ico_lbl->move(filename_edt->width() - warn_ico_lbl->width(),
70 										 (filename_edt->height() - warn_ico_lbl->height())/2);
71 }
72 
setAllowFilenameInput(bool allow_fl_input)73 void FileSelectorWidget::setAllowFilenameInput(bool allow_fl_input)
74 {
75 	allow_filename_input = allow_fl_input && !read_only;
76 	filename_edt->setReadOnly(!allow_filename_input);
77 }
78 
setFileMode(QFileDialog::FileMode file_mode)79 void FileSelectorWidget::setFileMode(QFileDialog::FileMode file_mode)
80 {
81 	// Forcing the ExistingFile (single file selection) if multiple file selection is provided
82 	if(file_mode == QFileDialog::ExistingFiles)
83 		file_mode = QFileDialog::ExistingFile;
84 	else if(file_mode == QFileDialog::Directory)
85 		file_mode = QFileDialog::DirectoryOnly;
86 
87 	file_dlg.setFileMode(file_mode);
88 	validateSelectedFile();
89 }
90 
setAcceptMode(QFileDialog::AcceptMode accept_mode)91 void FileSelectorWidget::setAcceptMode(QFileDialog::AcceptMode accept_mode)
92 {
93 	file_dlg.setAcceptMode(accept_mode);
94 }
95 
setNameFilters(const QStringList & filters)96 void FileSelectorWidget::setNameFilters(const QStringList &filters)
97 {
98 	file_dlg.setNameFilters(filters);
99 }
100 
setFileDialogTitle(const QString & title)101 void FileSelectorWidget::setFileDialogTitle(const QString &title)
102 {
103 	file_dlg.setWindowTitle(title);
104 }
105 
setSelectedFile(const QString & file)106 void FileSelectorWidget::setSelectedFile(const QString &file)
107 {
108 	filename_edt->setText(file);
109 }
110 
setMimeTypeFilters(const QStringList & filters)111 void FileSelectorWidget::setMimeTypeFilters(const QStringList &filters)
112 {
113 	file_dlg.setMimeTypeFilters(filters);
114 }
115 
setDefaultSuffix(const QString & suffix)116 void FileSelectorWidget::setDefaultSuffix(const QString &suffix)
117 {
118 	file_dlg.setDefaultSuffix(suffix);
119 }
120 
hasWarning()121 bool FileSelectorWidget::hasWarning()
122 {
123 	QString str = warn_ico_lbl->toolTip();
124 	return !warn_ico_lbl->toolTip().isEmpty();
125 }
126 
getSelectedFile()127 QString FileSelectorWidget::getSelectedFile()
128 {
129 	return filename_edt->text();
130 }
131 
clearCustomWarning()132 void FileSelectorWidget::clearCustomWarning()
133 {
134 	warn_ico_lbl->setToolTip("");
135 	showWarning();
136 }
137 
setReadOnly(bool value)138 void FileSelectorWidget::setReadOnly(bool value)
139 {
140 	read_only = value;
141 	filename_edt->setReadOnly(value);
142 	allow_filename_input = false;
143 
144 	sel_file_tb->setToolTip(value ? tr("Open in file manager") : tr("Select file"));
145 	rem_file_tb->setVisible(!value);
146 
147 	if(value)
148 	{
149 		disconnect(sel_file_tb, SIGNAL(clicked(bool)), this, SLOT(openFileDialog()));
150 		connect(sel_file_tb, SIGNAL(clicked(bool)), this, SLOT(openFileExternally()));
151 	}
152 	else
153 	{
154 		connect(sel_file_tb, SIGNAL(clicked(bool)), this, SLOT(openFileDialog()));
155 		disconnect(sel_file_tb, SIGNAL(clicked(bool)), this, SLOT(openFileExternally()));
156 	}
157 }
158 
setToolTip(const QString & tooltip)159 void FileSelectorWidget::setToolTip(const QString &tooltip)
160 {
161 	filename_edt->setToolTip(tooltip);
162 }
163 
setCustomWarning(const QString & warn_msg)164 void FileSelectorWidget::setCustomWarning(const QString &warn_msg)
165 {
166 	warn_ico_lbl->setToolTip(warn_msg);
167 	showWarning();
168 }
169 
openFileDialog()170 void FileSelectorWidget::openFileDialog()
171 {
172 	filename_edt->clearFocus();
173 	file_dlg.selectFile(filename_edt->text());
174 	file_dlg.exec();
175 
176 	if(file_dlg.result() == QDialog::Accepted && !file_dlg.selectedFiles().isEmpty())
177 	{
178 		filename_edt->setText(file_dlg.selectedFiles().at(0));
179 		emit s_fileSelected(file_dlg.selectedFiles().at(0));
180 	}
181 }
182 
openFileExternally()183 void FileSelectorWidget::openFileExternally()
184 {
185 	QDesktopServices::openUrl(QUrl(QString("file://") + filename_edt->text()));
186 }
187 
showWarning()188 void FileSelectorWidget::showWarning()
189 {
190 	QPalette pal;
191 	int padding = 0;
192 	bool has_warn = !warn_ico_lbl->toolTip().isEmpty();
193 
194 	warn_ico_lbl->setVisible(has_warn);
195 
196 	if(has_warn)
197 	{
198 		pal.setColor(QPalette::Text, QColor(255, 0, 0));
199 		padding = warn_ico_lbl->width();
200 	}
201 	else
202 		pal = qApp->palette();
203 
204 	filename_edt->setStyleSheet(QString("padding: 2px %1px 2px 1px").arg(padding));
205 	filename_edt->setPalette(pal);
206 }
207 
validateSelectedFile()208 void FileSelectorWidget::validateSelectedFile()
209 {
210 	QFileInfo fi(filename_edt->text());
211 	warn_ico_lbl->setToolTip("");
212 
213 	if(!filename_edt->text().isEmpty())
214 	{
215 		if(fi.exists() && fi.isDir() && file_dlg.fileMode() != QFileDialog::DirectoryOnly)
216 			warn_ico_lbl->setToolTip(tr("The provided path is not a file!"));
217 		else if(fi.exists() && fi.isFile() && file_dlg.fileMode() == QFileDialog::DirectoryOnly)
218 			warn_ico_lbl->setToolTip(tr("The provided path is not a directory!"));
219 		else if(!fi.exists() && file_dlg.fileMode() != QFileDialog::AnyFile)
220 		{
221 			if(file_dlg.fileMode() == QFileDialog::DirectoryOnly)
222 				warn_ico_lbl->setToolTip(tr("No such directory!"));
223 			else
224 				warn_ico_lbl->setToolTip(tr("No such file!"));
225 		}
226 	}
227 
228 	showWarning();
229 }
230 
clearSelector()231 void FileSelectorWidget::clearSelector()
232 {
233 	filename_edt->clear();
234 	filename_edt->clearFocus();
235 	rem_file_tb->setEnabled(false);
236 
237 	emit s_selectorCleared();
238 	emit s_selectorChanged(false);
239 }
240