Source code for spinetoolbox.widgets.project_form_widget
######################################################################################################################
# Copyright (C) 2017-2020 Spine project consortium
# This file is part of Spine Toolbox.
# Spine Toolbox is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General
# Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option)
# any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
# Public License for more details. You should have received a copy of the GNU Lesser General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
######################################################################################################################
"""
Widget shown to user when a new project is created.
:authors: P. Savolainen (VTT)
:date: 10.1.2018
"""
import os
from PySide2.QtWidgets import QWidget, QFileDialog, QMessageBox
from PySide2.QtCore import Slot, Qt, QStandardPaths
from ..config import INVALID_CHARS, APPLICATION_PATH
[docs]class NewProjectForm(QWidget):
"""Class for a new project widget."""
def __init__(self, toolbox):
"""
Args:
toolbox (ToolboxUI): Parent widget.
"""
from ..ui import project_form
super().__init__(parent=toolbox, f=Qt.Window) # Inherits stylesheet from parent
self._toolbox = toolbox
# Set up the user interface from Designer.
self.ui = project_form.Ui_Form()
self.ui.setupUi(self)
# Class attributes
self.dir = ""
self.name = "" # Project name
self.description = "" # Project description
self.connect_signals()
self.ui.pushButton_ok.setDefault(True)
# Ensure this window gets garbage-collected when closed
self.setAttribute(Qt.WA_DeleteOnClose)
[docs] def connect_signals(self):
"""Connect signals to slots."""
self.ui.toolButton_select_project_dir.clicked.connect(self.select_project_dir)
self.ui.pushButton_ok.clicked.connect(self.ok_clicked)
self.ui.pushButton_cancel.clicked.connect(self.close)
@Slot(bool, name="select_project_dir")
[docs] def select_project_dir(self, checked=False):
"""Opens a file browser, where user can select a directory for the new project."""
# noinspection PyCallByClass, PyArgumentList
start_dir = QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation)
if not start_dir:
start_dir = APPLICATION_PATH
answer = QFileDialog.getExistingDirectory(self, "Select a project directory", start_dir)
if not answer: # Canceled (american-english), cancelled (british-english)
return
# Check that it's a directory
if not os.path.isdir(answer):
msg = "Selected thing is not a directory, please try again"
# noinspection PyCallByClass, PyArgumentList
QMessageBox.warning(self, "Invalid selection", msg)
return
self.ui.lineEdit_project_dir.setText(answer)
# Set a suggested name for the project
_, suggested_name = os.path.split(answer)
self.ui.lineEdit_project_name.setText(suggested_name)
self.ui.lineEdit_project_name.selectAll()
self.ui.lineEdit_project_name.setFocus()
@Slot(name="ok_clicked")
[docs] def ok_clicked(self):
"""Check that project name is valid and create project."""
self.dir = self.ui.lineEdit_project_dir.text()
if self.dir == "":
# noinspection PyCallByClass, PyArgumentList
QMessageBox.information(self, "Note", "Please select a project directory")
return
if os.path.isdir(os.path.join(self.dir, ".spinetoolbox")):
msg = (
"Directory \n\n{0}\n\nalready contains a Spine Toolbox project."
"\nWould you like to overwrite the existing project?".format(self.dir)
)
message_box = QMessageBox(
QMessageBox.Question, "Overwrite?", msg, buttons=QMessageBox.Ok | QMessageBox.Cancel, parent=self
)
message_box.button(QMessageBox.Ok).setText("Overwrite")
answer = message_box.exec_()
if answer != QMessageBox.Ok:
return
self.name = self.ui.lineEdit_project_name.text()
self.description = self.ui.textEdit_description.toPlainText()
if self.name == "":
# noinspection PyCallByClass, PyArgumentList
QMessageBox.information(self, "Note", "Please give the project a name")
return
# Check for invalid characters for a folder name
if any((True for x in self.name if x in INVALID_CHARS)):
# noinspection PyCallByClass, PyArgumentList
QMessageBox.warning(
self,
"Invalid name",
"Project name contains invalid character(s)."
"\nCharacters {0} are not allowed.".format(" ".join(INVALID_CHARS)),
)
return
# Create new project
self.call_create_project()
self.close()
[docs] def call_create_project(self):
"""Call ToolboxUI method create_project()."""
self._toolbox.create_project(self.name, self.description, self.dir)
[docs] def keyPressEvent(self, e):
"""Close project form when escape key is pressed.
Args:
e (QKeyEvent): Received key press event.
"""
if e.key() == Qt.Key_Escape:
self.close()
elif e.key() == Qt.Key_Enter or e.key() == Qt.Key_Return:
self.ok_clicked()
[docs] def closeEvent(self, event=None):
"""Handle close window.
Args:
event (QEvent): Closing event if 'X' is clicked.
"""
if event:
event.accept()