/* * NewDirectoryPage.java * * Copyright (C) 2009-12 by RStudio, Inc. * * Unless you have received this program directly from RStudio pursuant * to the terms of a commercial license agreement with RStudio, then * this program is licensed to you under the terms of version 3 of the * GNU Affero General Public License. This program is distributed WITHOUT * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. * */ package org.rstudio.studio.client.projects.ui.newproject; import org.rstudio.core.client.Debug; import org.rstudio.core.client.files.FileSystemItem; import org.rstudio.core.client.js.JsUtil; import org.rstudio.core.client.resources.ImageResource2x; import org.rstudio.core.client.widget.MessageDialog; import org.rstudio.core.client.widget.OperationWithInput; import org.rstudio.core.client.widget.SelectWidget; import org.rstudio.studio.client.RStudioGinjector; import org.rstudio.studio.client.projects.Projects; import org.rstudio.studio.client.projects.model.NewPackageOptions; import org.rstudio.studio.client.projects.model.NewProjectInput; import org.rstudio.studio.client.projects.model.NewProjectResult; import org.rstudio.studio.client.server.ServerError; import org.rstudio.studio.client.server.ServerRequestCallback; import org.rstudio.studio.client.workbench.views.files.model.DirectoryListing; import org.rstudio.studio.client.workbench.views.files.model.FilesServerOperations; import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.KeyDownEvent; import com.google.gwt.event.dom.client.KeyDownHandler; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.inject.Inject; public class NewPackagePage extends NewDirectoryPage { public NewPackagePage() { super("R Package", "Create a new R package", "Create R Package", new ImageResource2x(NewProjectResources.INSTANCE.packageIcon2x()), new ImageResource2x(NewProjectResources.INSTANCE.packageIconLarge2x())); RStudioGinjector.INSTANCE.injectMembers(this); styles_ = NewProjectResources.INSTANCE.styles(); txtProjectName_.addKeyDownHandler(new KeyDownHandler() { @Override public void onKeyDown(KeyDownEvent event) { Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { validatePackageName(); } }); } }); } @Inject private void initialize(FilesServerOperations server) { server_ = server; } protected boolean getOptionsSideBySide() { return true; } @Override protected void onAddTopPanelWidgets(HorizontalPanel panel) { dirNameLabel_.setText("Package name:"); String[] labels = {"Package"}; String[] values = {"package"}; listProjectType_ = new SelectWidget("Type:", labels, values, false); listProjectType_.addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { txtProjectName_.setFocus(true); } }); panel.add(listProjectType_); } @Override protected void onAddBodyWidgets() { // code files panel listCodeFiles_ = new CodeFilesList(); addWidget(listCodeFiles_); } @Override protected void initialize(NewProjectInput input) { super.initialize(input); if (input.getContext().isRcppAvailable()) listProjectType_.addChoice("Package w/ Rcpp", "package-rcpp"); } @Override public void focus() { super.focus(); } @Override protected NewPackageOptions getNewPackageOptions() { return NewPackageOptions.create( getProjectName(), listProjectType_.getValue().equals("package-rcpp"), JsUtil.toJsArrayString(listCodeFiles_.getCodeFiles())); } private void validatePackageName() { String packageName = txtProjectName_.getText().trim(); // Don't validate if the name is empty if (packageName.isEmpty() || isPackageNameValid(packageName)) txtProjectName_.removeStyleName(styles_.invalidPkgName()); else txtProjectName_.addStyleName(styles_.invalidPkgName()); } private boolean isPackageNameValid(String packageName) { return Projects.PACKAGE_NAME_PATTERN.test(packageName); } @Override protected void validateAsync(final NewProjectResult input, final OperationWithInput<Boolean> onValidated) { // validate package name first String packageName = txtProjectName_.getText().trim(); if (!isPackageNameValid(packageName)) { globalDisplay_.showMessage( MessageDialog.WARNING, "Error", "Invalid package name '" + packageName + "'. Package names " + "should start with a letter, and contain only letters and numbers."); onValidated.execute(false); return; } final FileSystemItem projFile = FileSystemItem.createFile(input.getProjectFile()); final FileSystemItem projDir = projFile.getParentPath(); server_.stat(projDir.getPath(), new ServerRequestCallback<FileSystemItem>() { @Override public void onResponseReceived(final FileSystemItem item) { // no file at this path -- safe for use if (!item.exists()) { onValidated.execute(true); return; } // if it was a file, bail if (!item.isDirectory()) { globalDisplay_.showMessage( MessageDialog.WARNING, "Error", "A file already exists at path '" + item.getPath() + "'"); onValidated.execute(false); return; } // check if this directory is empty server_.listFiles(item, false, new ServerRequestCallback<DirectoryListing>() { @Override public void onResponseReceived(DirectoryListing listing) { boolean ok = true; JsArray<FileSystemItem> children = listing.getFiles(); for (FileSystemItem child : JsUtil.asIterable(children)) { boolean canIgnore = child.getExtension().equals(".Rproj") || child.getName().startsWith("."); if (canIgnore) continue; ok = false; break; } if (!ok) { globalDisplay_.showMessage( MessageDialog.WARNING, "Error", "Directory '" + item.getPath() + "' already exists and is not empty."); } onValidated.execute(ok); } @Override public void onError(ServerError error) { Debug.logError(error); onValidated.execute(true); } }); } @Override public void onError(ServerError error) { Debug.logError(error); onValidated.execute(true); } }); } private SelectWidget listProjectType_; private CodeFilesList listCodeFiles_; private final NewProjectResources.Styles styles_; // Injected ---- private FilesServerOperations server_; }