1 /*
2  * Stellarium
3  *
4  * Copyright (C) 2010 Bogdan Marinov (add/remove landscapes feature)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
19 */
20 #include "AddRemoveLandscapesDialog.hpp"
21 #include "ui_addRemoveLandscapesDialog.h"
22 
23 #include "Dialog.hpp"
24 #include "LandscapeMgr.hpp"
25 #include "StelApp.hpp"
26 #include "StelModuleMgr.hpp"
27 #include "StelLocaleMgr.hpp"
28 #include "StelMainView.hpp"
29 
30 #include <QDebug>
31 #include <QFileDialog>
32 #include <QString>
33 #include <QMessageBox>
34 
AddRemoveLandscapesDialog()35 AddRemoveLandscapesDialog::AddRemoveLandscapesDialog() : StelDialog("AddRemoveLandscapes")
36 {
37 	ui = new Ui_addRemoveLandscapesDialogForm;
38 	landscapeManager = GETSTELMODULE(LandscapeMgr);
39 	lastUsedDirectoryPath = QDir::homePath();
40 }
41 
~AddRemoveLandscapesDialog()42 AddRemoveLandscapesDialog::~AddRemoveLandscapesDialog()
43 {
44 	delete ui;
45 }
46 
retranslate()47 void AddRemoveLandscapesDialog::retranslate()
48 {
49 	if (dialog)
50 		ui->retranslateUi(dialog);
51 }
52 
53 // Initialize the dialog widgets and connect the signals/slots
createDialogContent()54 void AddRemoveLandscapesDialog::createDialogContent()
55 {
56 	ui->setupUi(dialog);
57 
58 	//Signals and slots
59 	connect(&StelApp::getInstance(), SIGNAL(languageChanged()), this, SLOT(retranslate()));
60 	connect(ui->closeStelWindow, SIGNAL(clicked()), this, SLOT(close()));
61 	connect(ui->TitleBar, SIGNAL(movedTo(QPoint)), this, SLOT(handleMovedTo(QPoint)));
62 
63 	connect(ui->pushButtonBrowseForArchive, SIGNAL(clicked()), this, SLOT(browseForArchiveClicked()));
64 	connect(ui->listWidgetUserLandscapes, SIGNAL(currentRowChanged(int)), this, SLOT(updateSidePane(int)));
65 	connect(ui->pushButtonRemove, SIGNAL(clicked()), this, SLOT(removeClicked()));
66 	connect(ui->pushButtonMessageOK, SIGNAL(clicked()), this, SLOT(messageAcknowledged()));
67 
68 	connect(landscapeManager, SIGNAL(landscapesChanged()), this, SLOT(populateLists()));
69 	connect(landscapeManager, SIGNAL(errorUnableToOpen(QString)), this, SLOT(messageUnableToOpen(QString)));
70 	connect(landscapeManager, SIGNAL(errorNotArchive()), this, SLOT(messageNotArchive()));
71 	connect(landscapeManager, SIGNAL(errorNotUnique(QString)), this, SLOT(messageNotUnique(QString)));
72 	connect(landscapeManager, SIGNAL(errorRemoveManually(QString)), this, SLOT(messageRemoveManually(QString)));
73 
74 	ui->groupBoxMessage->setVisible(false);
75 
76 	populateLists();
77 }
78 
setVisible(bool v)79 void AddRemoveLandscapesDialog::setVisible(bool v)
80 {
81 	StelDialog::setVisible(v);
82 	//Make sure that every time when the dialog is displayed, the current
83 	//landscape is selected in the list of user landscapes if it is in the list.
84 	populateLists();
85 }
86 
populateLists()87 void AddRemoveLandscapesDialog::populateLists()
88 {
89 	ui->listWidgetUserLandscapes->clear();
90 	QStringList landscapes = landscapeManager->getUserLandscapeIDs();
91 	if (!landscapes.isEmpty())
92 	{
93 		landscapes.sort();
94 		ui->listWidgetUserLandscapes->addItems(landscapes);
95 		//If the current landscape is in the list of user landscapes, select its entry
96 		if((ui->listWidgetUserLandscapes->findItems(landscapeManager->getCurrentLandscapeID(), Qt::MatchExactly).isEmpty()))
97 		{
98 			//If the current landscape is not in the list, simply select the first row
99 			ui->listWidgetUserLandscapes->setCurrentRow(0);
100 		}
101 		else
102 		{
103 			ui->listWidgetUserLandscapes->setCurrentItem(ui->listWidgetUserLandscapes->findItems(landscapeManager->getCurrentLandscapeID(), Qt::MatchExactly).first());
104 		}
105 	}
106 	else
107 	{
108 		//Force disabling the side pane
109 		updateSidePane(-1);
110 	}
111 }
112 
browseForArchiveClicked()113 void AddRemoveLandscapesDialog::browseForArchiveClicked()
114 {
115 	QString caption = q_("Select a ZIP archive that contains a Stellarium landscape");
116 	// TRANSLATORS: This string is displayed in the "Files of type:" drop-down list in the standard file selection dialog.
117 	QString filter = q_("ZIP archives");
118 	filter += " (*.zip)";
119 	QString sourceArchivePath = QFileDialog::getOpenFileName(Q_NULLPTR, caption, lastUsedDirectoryPath, filter);
120 	bool useLandscape = ui->checkBoxUseLandscape->isChecked();
121 	if (!sourceArchivePath.isEmpty() && QFile::exists(sourceArchivePath))
122 	{
123 		//Remember the last successfully used directory
124 		lastUsedDirectoryPath = QFileInfo(sourceArchivePath).path();
125 
126 		QString newLandscapeID = landscapeManager->installLandscapeFromArchive(sourceArchivePath, useLandscape);
127 		if(!newLandscapeID.isEmpty())
128 		{
129 			//Show a message
130 			QString successMessage  = QString(q_("Landscape \"%1\" has been installed successfully.")).arg(newLandscapeID);
131 			displayMessage(q_("Success"), successMessage);
132 
133 			//Make the new landscape selected in the list
134 			//populateLists(); //No longer needed after the migration to signals/slots
135 			ui->listWidgetUserLandscapes->setCurrentItem((ui->listWidgetUserLandscapes->findItems(newLandscapeID, Qt::MatchExactly)).first());
136 		}
137 		else
138 		{
139 			//If no error message has been displayed by the signal/slot mechanism,
140 			//display a generic message.
141 			if (!ui->groupBoxMessage->isVisible())
142 			{
143 				//Show an error message
144 				QString failureMessage = q_("No landscape was installed.");
145 				displayMessage(q_("Error!"), failureMessage);
146 			}
147 		}
148 	}
149 }
150 
removeClicked()151 void AddRemoveLandscapesDialog::removeClicked()
152 {
153 	int reply = QMessageBox(QMessageBox::Question,
154 				q_("Remove an installed landscape"),
155 				q_("Do you really want to remove this landscape?"),
156                 QMessageBox::Yes|QMessageBox::No,
157                 &StelMainView::getInstance()).exec();
158 
159 	if (reply == QMessageBox::Yes)
160 	{
161 		QString landscapeID = ui->listWidgetUserLandscapes->currentItem()->data(0).toString();
162 		if(landscapeManager->removeLandscape(landscapeID))
163 		{
164 			//populateLists();//No longer needed after the migration to signals/slots
165 			QString successMessage  = QString(q_("Landscape \"%1\" has been removed successfully.")).arg(landscapeID);
166 			displayMessage(q_("Success"), successMessage);
167 		}
168 		else
169 		{
170 			//If no error message has been displayed by the signal/slot mechanism,
171 			//display a generic message.
172 			if (!ui->groupBoxMessage->isVisible())
173 			{
174 				//Show an error message
175 				//NB! This string is used elsewhere. Modify both to avoid two nearly identical translations.
176 				QString failureMessage = q_("The selected landscape could not be (completely) removed.");
177 				displayMessage(q_("Error!"), failureMessage);
178 			}
179 		}
180 	}
181 }
182 
updateSidePane(int newRow)183 void AddRemoveLandscapesDialog::updateSidePane(int newRow)
184 {
185 	bool displaySidePane = (newRow >= 0);
186 	ui->labelLandscapeName->setVisible(displaySidePane);
187 	ui->labelLandscapeSize->setVisible(displaySidePane);
188 	ui->pushButtonRemove->setEnabled(displaySidePane);
189 	ui->labelWarning->setEnabled(displaySidePane);
190 	if (!displaySidePane)
191 		return;
192 
193 	QString landscapeID = ui->listWidgetUserLandscapes->item(newRow)->data(0).toString();
194 	//Name
195 	ui->labelLandscapeName->setText("<h3>"+landscapeManager->loadLandscapeName(landscapeID)+"</h3>");
196 	//Size in MiB
197 	double landscapeSize = landscapeManager->loadLandscapeSize(landscapeID) / static_cast<double>(1024*1024);
198 	// TRANSLATORS: MiB = mebibytes (IEC 60027-2 standard for 2^20 bytes)
199 	ui->labelLandscapeSize->setText(QString(q_("Size on disk: %1 MiB")).arg(landscapeSize, 0, 'f', 2));
200 }
201 
messageAcknowledged()202 void AddRemoveLandscapesDialog::messageAcknowledged()
203 {
204 	ui->groupBoxMessage->setVisible(false);
205 	ui->groupBoxAdd->setVisible(true);
206 	ui->groupBoxRemove->setVisible(true);
207 	ui->labelMessage->clear();
208 	ui->groupBoxMessage->setTitle(QString());
209 }
210 
displayMessage(QString title,QString message)211 void AddRemoveLandscapesDialog::displayMessage(QString title, QString message)
212 {
213 	ui->labelMessage->setText(message);
214 	ui->groupBoxMessage->setTitle(title);
215 	ui->groupBoxMessage->setVisible(true);
216 	ui->groupBoxAdd->setVisible(false);
217 	ui->groupBoxRemove->setVisible(false);
218 }
219 
messageUnableToOpen(QString path)220 void AddRemoveLandscapesDialog::messageUnableToOpen(QString path)
221 {
222 	QString failureMessage = q_("No landscape was installed.");
223 	failureMessage.append(" ");
224 	// TRANSLATORS: The parameter is a file/directory path that may be quite long.
225 	failureMessage.append(q_("Stellarium cannot open for reading or writing %1").arg(path));
226 	displayMessage(q_("Error!"), failureMessage);
227 }
228 
messageNotArchive()229 void AddRemoveLandscapesDialog::messageNotArchive()
230 {
231 	QString failureMessage = q_("No landscape was installed.") + " " + q_("The selected file is not a ZIP archive or does not contain a Stellarium landscape.");
232 	displayMessage(q_("Error!"), failureMessage);
233 }
234 
messageNotUnique(QString nameOrID)235 void AddRemoveLandscapesDialog::messageNotUnique(QString nameOrID)
236 {
237 	// TRANSLATORS: The parameter is the duplicate name or identifier.
238 	QString nameMessage = q_("A landscape with the same name or identifier (%1) already exists.").arg(nameOrID);
239 	QString failureMessage = q_("No landscape was installed.") + " " + nameMessage;
240 	displayMessage(q_("Error!"), failureMessage);
241 }
242 
messageRemoveManually(QString path)243 void AddRemoveLandscapesDialog::messageRemoveManually(QString path)
244 {
245 	//NB! This string is used elsewhere. Modify both to avoid two nearly identical translations.
246 	QString failureMessage = q_("The selected landscape could not be (completely) removed.");
247 	failureMessage.append(" ");
248 	// TRANSLATORS: The parameter is a file/directory path that may be quite long. "It" refers to a landscape that can't be removed.
249 	failureMessage.append(q_("You can remove it manually by deleting the following directory: %1").arg(path));
250 	displayMessage(q_("Error!"), failureMessage);
251 }
252