# -*- coding: utf-8 -*-
#
# This file is part of NINJA-IDE (http://ninja-ide.org).
#
# NINJA-IDE is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# any later version.
#
# NINJA-IDE 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with NINJA-IDE; If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
import os
import sys
from PyQt4.QtGui import QWizard
from PyQt4.QtGui import QWizardPage
from PyQt4.QtGui import QLabel
from PyQt4.QtGui import QPushButton
from PyQt4.QtGui import QComboBox
from PyQt4.QtGui import QLineEdit
from PyQt4.QtGui import QPlainTextEdit
from PyQt4.QtGui import QGridLayout
from PyQt4.QtGui import QVBoxLayout
from PyQt4.QtGui import QHBoxLayout
from PyQt4.QtGui import QMessageBox
from PyQt4.QtGui import QFileDialog
from PyQt4.QtGui import QListWidget
from PyQt4.QtGui import QCompleter
from PyQt4.QtGui import QDirModel
from PyQt4.QtGui import QPixmap
from PyQt4.QtCore import Qt
from PyQt4.QtCore import SIGNAL
from ninja_ide import resources
from ninja_ide.core import settings
from ninja_ide.core import plugin_interfaces
from ninja_ide.core.file_handling import file_manager
from ninja_ide.tools import json_manager
from ninja_ide.tools.logger import NinjaLogger
logger = NinjaLogger('ninja_ide.gui.dialogs.wizard_new_project')
logger.info("loaded")
DEBUG = logger.debug
###############################################################################
# Wizard handler and Python Project handler
###############################################################################
class WizardNewProject(QWizard):
"""
Wizard to create a new project (of any kind), it implements the base
behavior. Also, it set two special projects type handler
(PythonProjectHandler, ImportFromSourcesProjectHandler)
"""
def __init__(self, parent):
QWizard.__init__(self, parent)
self.__explorer = parent
self.setWindowTitle(self.tr("NINJA - New Project Wizard"))
self.setPixmap(QWizard.LogoPixmap, QPixmap(resources.IMAGES['icon']))
self.option = 'Python'
#Add a project type handler for Python
settings.set_project_type_handler(self.option,
PythonProjectHandler(self.__explorer))
#Add a project type handler for Import from existing sources
settings.set_project_type_handler('Import from sources',
ImportFromSourcesProjectHandler(self.__explorer))
self.projectTypePage = PageProjectType(self)
self.addPage(self.projectTypePage)
self.addPage(PageProjectProperties())
self.setButtonLayout([
QWizard.BackButton,
QWizard.Stretch,
QWizard.NextButton,
QWizard.FinishButton])
def add_project_pages(self, option='Python'):
logger.debug("Add project pages")
self.option = option
pages = settings.get_project_type_handler(option).get_pages()
listIds = self.pageIds()
listIds.pop(listIds.index(0))
for page in pages:
self.addPage(page)
#this page is always needed by a project!
self.addPage(PageProjectProperties())
for i in listIds:
self.removePage(i)
def done(self, result):
logger.debug("Done")
if result == 1:
page = self.currentPage()
if type(page) == PageProjectProperties:
venv = page.vtxtPlace.text()
if venv:
if sys.platform == 'win32':
venv = os.path.join(venv, 'Scripts', 'python.exe')
else:
venv = os.path.join(venv, 'bin', 'python')
#check if venv folder exists
if not os.path.exists(venv):
btnPressed = QMessageBox.information(self,
self.tr("Virtualenv Folder"),
self.tr("Folder don't exists or this is not a "
"valid Folder.\n If you want to set "
"or modify, go to project properties"),
self.tr("Back"),
self.tr("Continue"))
if btnPressed == QMessageBox.NoButton:
return
else:
self.currentPage().vtxtPlace.setText("")
page.vtxtPlace.setText(venv)
settings.get_project_type_handler(self.option)\
.on_wizard_finish(self)
super(WizardNewProject, self).done(result)
def _load_project(self, path):
"""
Open Project based on path into Explorer
"""
self.__explorer.open_project_folder(path)
def _load_project_with_extensions(self, path, extensions):
"""Open Project based on path into Explorer with extensions"""
# self._main._properties._treeProjects.load_project(
# self._main.open_project_with_extensions(path), path)
pass
###############################################################################
# Python Project Handler
###############################################################################
class PythonProjectHandler(plugin_interfaces.IProjectTypeHandler):
"""
Handler for Python projects
"""
def __init__(self, explorer):
self.__explorer = explorer
def get_pages(self):
"""
Get extra pages for new Python projects
"""
return ()
def get_context_menus(self):
"""
Get a special menu for new Python projects
"""
return ()
def on_wizard_finish(self, wizard):
"""
Create the ninja_porject (.nja file), create the main __init__.py
and open the project
"""
ids = wizard.pageIds()
page = wizard.page(ids[1])
name = page.txtName.text()
path = os.path.join(page.txtPlace.text(), name)
if not path:
QMessageBox.critical(self, self.tr("Incorrect Location"),
self.tr("The project couldn\'t be create"))
return
if not os.path.exists(path):
os.makedirs(path)
project = {}
project['name'] = name
project['description'] = page.txtDescription.toPlainText()
project['license'] = page.cboLicense.currentText()
project['venv'] = page.vtxtPlace.text()
json_manager.create_ninja_project(path, name, project)
try:
file_manager.create_init_file(path)
except:
logger.debug("The __init__ file already exists - Import Sources.")
wizard._load_project(path)
###############################################################################
# Import project from existing sources
###############################################################################
class ImportFromSourcesProjectHandler(plugin_interfaces.IProjectTypeHandler):
"""
Handler for Import from existing sources project
"""
def __init__(self, explorer):
self.__explorer = explorer
def get_pages(self):
"""
Get extra pages for Import from sources projects
"""
return ()
def get_context_menus(self):
"""
Get a special menu for Import from sources projects
"""
return ()
def on_wizard_finish(self, wizard):
"""
Create the ninja_porject (.nja file) and open the project
"""
ids = wizard.pageIds()
page = wizard.page(ids[1])
name = page.txtName.text()
path = page.txtPlace.text()
if not path:
QMessageBox.critical(self, self.tr("Incorrect Location"),
self.tr("The project couldn\'t be create"))
return
project = {}
project['name'] = name
project['description'] = page.txtDescription.toPlainText()
project['license'] = page.cboLicense.currentText()
project['venv'] = page.vtxtPlace.text()
project['project-type'] = wizard.option
json_manager.create_ninja_project(path, name, project)
wizard._load_project(path)
###############################################################################
# WIZARD FIRST PAGE
###############################################################################
class PageProjectType(QWizardPage):
def __init__(self, wizard):
QWizardPage.__init__(self)
self.setTitle(self.tr("Project Type"))
self.setSubTitle(self.tr("Choose the Project Type"))
self._wizard = wizard
vbox = QVBoxLayout(self)
self.listWidget = QListWidget()
vbox.addWidget(self.listWidget)
types = settings.get_all_project_types()
types.sort()
index = types.index('Python')
types.insert(0, types.pop(index))
self.listWidget.addItems(types)
self.listWidget.setCurrentRow(0)
self.connect(self.listWidget,
SIGNAL("itemClicked(QListWidgetItem *)"),
self.load_pages)
def validatePage(self):
self._wizard.option = self.listWidget.currentItem().text()
return True
def load_pages(self):
self.wizard().add_project_pages(self.listWidget.currentItem().text())
###############################################################################
# WIZARD LAST PAGE
###############################################################################
class PageProjectProperties(QWizardPage):
def __init__(self):
QWizardPage.__init__(self)
self.setTitle(self.tr("New Project Data"))
self.setSubTitle(self.tr(
"Complete the following fields to create the Project Structure"))
gbox = QGridLayout(self)
#Names of the fields to complete
self.lblName = QLabel(self.tr("New Project Name (*):"))
self.lblPlace = QLabel(self.tr("Create in (*):"))
self.lblDescription = QLabel(self.tr("Project Description:"))
self.lblLicense = QLabel(self.tr("Project License:"))
self.lblVenvFolder = QLabel(self.tr("Virtualenv Folder:"))
gbox.addWidget(self.lblName, 0, 0, Qt.AlignRight)
gbox.addWidget(self.lblPlace, 1, 0, Qt.AlignRight)
gbox.addWidget(self.lblDescription, 2, 0, Qt.AlignTop)
gbox.addWidget(self.lblLicense, 3, 0, Qt.AlignRight)
gbox.addWidget(self.lblVenvFolder, 4, 0, Qt.AlignRight)
#Fields on de right of the grid
#Name
self.txtName = QLineEdit()
#Location
hPlace = QHBoxLayout()
self.txtPlace = QLineEdit()
self.txtPlace.setReadOnly(True)
self.btnExamine = QPushButton(self.tr("Browse..."))
hPlace.addWidget(self.txtPlace)
hPlace.addWidget(self.btnExamine)
#Virtualenv
vPlace = QHBoxLayout()
self.vtxtPlace = QLineEdit()
self._dir_completer = QCompleter()
self._dir_completer.setModel(QDirModel(self._dir_completer))
self.vtxtPlace.setCompleter(self._dir_completer)
self.vbtnExamine = QPushButton(self.tr("Browse..."))
vPlace.addWidget(self.vtxtPlace)
vPlace.addWidget(self.vbtnExamine)
#Project Description
self.txtDescription = QPlainTextEdit()
#Project License
self.cboLicense = QComboBox()
self.cboLicense.setFixedWidth(250)
self.cboLicense.addItem('Apache License 2.0')
self.cboLicense.addItem('Artistic License/GPL')
self.cboLicense.addItem('Eclipse Public License 1.0')
self.cboLicense.addItem('GNU General Public License v2')
self.cboLicense.addItem('GNU General Public License v3')
self.cboLicense.addItem('GNU Lesser General Public License')
self.cboLicense.addItem('MIT License')
self.cboLicense.addItem('Mozilla Public License 1.1')
self.cboLicense.addItem('Mozilla Public License 2.0')
self.cboLicense.addItem('New BSD License')
self.cboLicense.addItem('Other Open Source')
self.cboLicense.addItem('Other')
self.cboLicense.setCurrentIndex(4)
#Add to Grid
gbox.addWidget(self.txtName, 0, 1)
gbox.addLayout(hPlace, 1, 1)
gbox.addWidget(self.txtDescription, 2, 1)
gbox.addWidget(self.cboLicense, 3, 1)
gbox.addLayout(vPlace, 4, 1)
#Signal
self.connect(self.btnExamine, SIGNAL('clicked()'), self.load_folder)
self.connect(self.vbtnExamine, SIGNAL('clicked()'),
self.load_folder_venv)
self.connect(self.txtName, SIGNAL('textChanged(const QString&)'),
lambda: self.emit(SIGNAL("completeChanged()")))
def isComplete(self):
name = self.txtName.text().strip()
place = self.txtPlace.text().strip()
return (len(name) > 0) and (len(place) > 0)
def load_folder(self):
self.txtPlace.setText(QFileDialog.getExistingDirectory(
self, self.tr("New Project Folder")))
self.emit(SIGNAL("completeChanged()"))
def load_folder_venv(self):
self.vtxtPlace.setText(QFileDialog.getExistingDirectory(
self, self.tr("Select Virtualenv Folder")))