001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.php.project;
042:
043: import java.io.BufferedInputStream;
044: import java.io.File;
045: import java.io.FileInputStream;
046: import java.io.IOException;
047: import java.io.InputStream;
048: import java.io.OutputStream;
049: import javax.swing.JFileChooser;
050: import org.netbeans.api.progress.ProgressHandle;
051: import org.netbeans.api.progress.ProgressHandleFactory;
052: import org.netbeans.api.project.Project;
053: import org.netbeans.modules.php.project.options.ProjectActionsPreferences;
054: import org.netbeans.modules.php.rt.utils.ActionsDialogs;
055: import org.openide.filesystems.FileLock;
056: import org.openide.filesystems.FileObject;
057: import org.openide.filesystems.FileUtil;
058: import org.openide.util.Cancellable;
059: import org.openide.util.NbBundle;
060: import org.openide.util.RequestProcessor;
061: import org.openide.windows.IOProvider;
062: import org.openide.windows.InputOutput;
063: import org.openide.windows.OutputWriter;
064: import org.openide.windows.WindowManager;
065:
066: /**
067: * @author ads
068: *
069: */
070: class ImportCommand extends AbstractCommand implements Cancellable {
071:
072: public static final String IMPORT_ACTION = "import"; // NOI18N
073: public static final String CHOOSE_FILES = "LBL_ChooseFiles"; // NOI18N
074: private static final String LABEL = PhpActionProvider.LBL_IMPORT_FILE;
075: static final String LBL_FILES_IMPORTED = "LBL_FilesImported"; // NOI18N
076: private static final String LBL_WARNING_MSG = "LBL_ImportWarningMsg"; // NOI18N
077:
078: //private static Logger LOGGER = Logger.getLogger(RunLocalCommand.class.getName());
079:
080: ImportCommand(Project project) {
081: super (project);
082: }
083:
084: /* (non-Javadoc)
085: * @see org.netbeans.modules.php.rt.spi.providers.Command#getId()
086: */
087: public String getId() {
088: return IMPORT_ACTION;
089: }
090:
091: /* (non-Javadoc)
092: * @see org.netbeans.modules.php.rt.spi.providers.Command#getLabel()
093: */
094: public String getLabel() {
095: return NbBundle.getMessage(ImportCommand.class, LABEL);
096: }
097:
098: /**
099: * This command should be started in AWT thread because it uses WindowsAPI.
100: * Will run copying routine in separate thread itself.
101: * @return false - it will be performed synchronously as called in the event thread.
102: */
103: @Override
104: public boolean asynchronous() {
105: return false;
106: }
107:
108: /* (non-Javadoc)
109: * @see java.lang.Runnable#run()
110: */
111: public void run() {
112: refresh();
113:
114: JFileChooser chooser = new JFileChooser();
115: chooser.setDialogTitle(NbBundle.getMessage(ImportCommand.class,
116: CHOOSE_FILES));
117: chooser
118: .setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
119: chooser.setMultiSelectionEnabled(true);
120:
121: if (JFileChooser.APPROVE_OPTION == chooser
122: .showOpenDialog(WindowManager.getDefault()
123: .getMainWindow())) {
124: File[] files = chooser.getSelectedFiles();
125: if (files == null) {
126: return;
127: }
128:
129: importFiles(files);
130: }
131: }
132:
133: protected void notifyFileImported() {
134: statusMsg(LBL_FILES_IMPORTED, ImportCommand.class);
135: }
136:
137: private void importFiles(final File[] files) {
138: Runnable importThread = new Runnable() {
139:
140: public void run() {
141: runImportFilesWithStatus(files);
142: }
143: };
144: RequestProcessor.getDefault().post(importThread);
145:
146: }
147:
148: private void runImportFilesWithStatus(File[] files) {
149: ProgressHandle progress = ProgressHandleFactory
150: .createHandle(getLabel());
151: progress.start();
152:
153: //initOutputTabWriter(getOutputTabTitle());
154:
155: try {
156: copyFiles(files);
157: } finally {
158: progress.finish();
159: closeOutputTabWriter();
160: }
161: }
162:
163: private OutputWriter initOutputTabWriter(String title) {
164: if (myOutputTabWriter != null) {
165: closeOutputTabWriter();
166: }
167: InputOutput io = IOProvider.getDefault().getIO(title, false);
168: io.select();
169: myOutputTabWriter = io.getOut();
170: return myOutputTabWriter;
171: }
172:
173: /**
174: * is used to log errors to output tab.
175: * Because inherited notifyMag creates writer for each msg.
176: * @param bundleKey
177: * @param args
178: */
179: private void logToOutputTab(String bundleKey, Object... args) {
180: if (myOutputTabWriter != null) {
181: String msg = loadFormattedMsg(bundleKey, getClass(), args);
182: myOutputTabWriter.println(msg);
183: myOutputTabWriter.flush();
184: } else {
185: initOutputTabWriter(getOutputTabTitle());
186: }
187: }
188:
189: private void closeOutputTabWriter() {
190: if (myOutputTabWriter != null) {
191: myOutputTabWriter.close();
192: myOutputTabWriter = null;
193: }
194: }
195:
196: private boolean copyFiles(File[] files) {
197: boolean[] success = new boolean[] { true };
198: File sourceRoot = FileUtil.toFile(getSourceObject());
199: for (File file : files) {
200: File to = new File(sourceRoot, file.getName());
201: if (skipTargetFile(to)) {
202: continue;
203: }
204: if (file.isDirectory()) {
205: copyFolder(success, file, to);
206: } else {
207: try {
208: to.getParentFile().mkdirs();
209: if (to.exists()) {
210: overwriteFile(file, to);
211: } else {
212: copyFile(file, to);
213: }
214: } catch (IOException e) {
215: logToOutputTab(LBL_WARNING_MSG, e.getMessage());
216: success[0] = false;
217: }
218: }
219: }
220: return success[0];
221: }
222:
223: private boolean skipTargetFile(File file) {
224: return isNbProject(file);
225: }
226:
227: private void copyFilesRecursively(File from, File to,
228: boolean[] errors) {
229: if (!from.isDirectory()) {
230: return;
231: }
232:
233: File[] children = from.listFiles();
234: for (File child : children) {
235: File dst = new File(to, child.getName());
236: //if (skipFile(child)) {
237: // continue;
238: //}
239: if (child.isDirectory()) {
240: copyFolder(errors, child, dst);
241: } else {
242: try {
243: if (dst.exists()) {
244: overwriteFile(child, dst);
245: } else {
246: copyFile(child, dst);
247: }
248: } catch (IOException e) {
249: logToOutputTab(LBL_WARNING_MSG, e.getMessage());
250: errors[0] = false;
251: }
252: }
253: }
254: }
255:
256: private void copyFolder(boolean[] errors, File src, File dst) {
257: boolean success = dst.mkdirs();
258: if (!success && !dst.exists()) {
259: errors[0] = false;
260: } else {
261: copyFilesRecursively(src, dst, errors);
262: }
263: }
264:
265: private void overwriteFile(File from, File to) throws IOException {
266: boolean overwrite = false;
267: String fileFullName = to.getPath();
268:
269: overwrite = getOverwriteFiles() == null
270: //? Boolean.TRUE
271: ? confirmOverwrite(fileFullName)
272: : getOverwriteFiles().booleanValue();
273:
274: if (overwrite) {
275: File toTmp = getNotExistingTmpFile(to);
276:
277: copyFile(from, toTmp);
278: to.delete();
279: toTmp.renameTo(to);
280: } else {
281: // do nothing
282: }
283: }
284:
285: private File getNotExistingTmpFile(File to) {
286: File toTmp = null;
287: do {
288: toTmp = getTmpFile(to);
289: } while (toTmp.exists());
290: return toTmp;
291: }
292:
293: private File getTmpFile(File to) {
294: File parentFolder = to.getParentFile();
295: File toTmp = new File(parentFolder, System.currentTimeMillis()
296: + to.getName() + PhpProject.TMP_FILE_POSTFIX);
297: return toTmp;
298: }
299:
300: static FileObject copyFile(File from, File to) throws IOException {
301: assert to != null;
302: assert from != null;
303:
304: // do not use the fiollowing code because File 'to' doesn't have method to
305: // get name without ext easily. FileUtil.copyFile needs name without ext.
306: //FileObject fromFileObject = FileUtil.toFileObject(FileUtil.normalizeFile(from));
307: //FileObject destFolder = FileUtil.toFileObject(to.getParentFile());
308: //if (fromFileObject != null && destFolder != null) {
309: // return FileUtil.copyFile(fromFileObject, destFolder, to.getName());
310: //}
311: FileObject dest = FileUtil.createData(to);
312:
313: FileLock lock = null;
314: InputStream bufIn = null;
315: OutputStream bufOut = null;
316:
317: try {
318: lock = dest.lock();
319: bufIn = new BufferedInputStream(new FileInputStream(from));
320:
321: bufOut = dest.getOutputStream(lock);
322:
323: FileUtil.copy(bufIn, bufOut);
324: } finally {
325: if (bufIn != null) {
326: bufIn.close();
327: }
328:
329: if (bufOut != null) {
330: bufOut.close();
331: }
332:
333: if (lock != null) {
334: lock.releaseLock();
335: }
336: }
337:
338: return dest;
339: }
340:
341: protected boolean confirmOverwrite(String file) {
342: Boolean overwriteFiles = getOverwriteFiles();
343: if (overwriteFiles != null) {
344: return overwriteFiles.booleanValue();
345: }
346: boolean[] dontAskConfirm = new boolean[] { false };
347: boolean confirm = ActionsDialogs.userConfirmRewrite(file,
348: dontAskConfirm);
349: if (dontAskConfirm[0]) {
350: ProjectActionsPreferences.getInstance().setFileOverwrite(
351: confirm);
352: }
353: return confirm;
354: }
355:
356: protected Boolean getOverwriteFiles() {
357: return ProjectActionsPreferences.getInstance()
358: .getFileOverwrite();
359: }
360:
361: /*
362: * implementation of org.openide.util.Cancellable
363: */
364:
365: public boolean cancel() {
366: return false;
367: }
368:
369: OutputWriter myOutputTabWriter = null;
370: }
|