PageRenderTime 27ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/netbeans-7.3/php.project/src/org/netbeans/modules/php/project/connections/sync/diff/DiffPanel.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 365 lines | 269 code | 29 blank | 67 comment | 39 complexity | 3b616149f76b9651fd5ff421c69cfc88 MD5 | raw file
  1. /*
  2. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  3. *
  4. * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
  5. *
  6. * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  7. * Other names may be trademarks of their respective owners.
  8. *
  9. * The contents of this file are subject to the terms of either the GNU
  10. * General Public License Version 2 only ("GPL") or the Common
  11. * Development and Distribution License("CDDL") (collectively, the
  12. * "License"). You may not use this file except in compliance with the
  13. * License. You can obtain a copy of the License at
  14. * http://www.netbeans.org/cddl-gplv2.html
  15. * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  16. * specific language governing permissions and limitations under the
  17. * License. When distributing the software, include this License Header
  18. * Notice in each file and include the License file at
  19. * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
  20. * particular file as subject to the "Classpath" exception as provided
  21. * by Oracle in the GPL Version 2 section of the License file that
  22. * accompanied this code. If applicable, add the following below the
  23. * License Header, with the fields enclosed by brackets [] replaced by
  24. * your own identifying information:
  25. * "Portions Copyrighted [year] [name of copyright owner]"
  26. *
  27. * If you wish your version of this file to be governed by only the CDDL
  28. * or only the GPL Version 2, indicate your decision by adding
  29. * "[Contributor] elects to include this software in this distribution
  30. * under the [CDDL or GPL Version 2] license." If you do not indicate a
  31. * single choice of license, a recipient has the option to distribute
  32. * your version of this file under either the CDDL, the GPL Version 2 or
  33. * to extend the choice of license to its licensees as provided above.
  34. * However, if you add GPL Version 2 code and therefore, elected the GPL
  35. * Version 2 license, then the option applies only if the new code is
  36. * made subject to such option by the copyright holder.
  37. *
  38. * Contributor(s):
  39. *
  40. * Portions Copyrighted 2012 Sun Microsystems, Inc.
  41. */
  42. package org.netbeans.modules.php.project.connections.sync.diff;
  43. import java.awt.BorderLayout;
  44. import java.awt.Dialog;
  45. import java.awt.Dimension;
  46. import java.io.File;
  47. import java.io.IOException;
  48. import java.io.InputStream;
  49. import java.io.OutputStream;
  50. import java.nio.charset.Charset;
  51. import java.util.List;
  52. import java.util.logging.Level;
  53. import java.util.logging.Logger;
  54. import javax.swing.JButton;
  55. import javax.swing.JLabel;
  56. import javax.swing.JPanel;
  57. import javax.swing.SwingConstants;
  58. import javax.swing.SwingUtilities;
  59. import org.netbeans.api.diff.DiffController;
  60. import org.netbeans.api.diff.StreamSource;
  61. import org.netbeans.modules.php.api.util.StringUtils;
  62. import org.netbeans.modules.php.project.connections.RemoteClient;
  63. import org.netbeans.modules.php.project.connections.RemoteException;
  64. import org.netbeans.modules.php.project.connections.TmpLocalFile;
  65. import org.netbeans.modules.php.project.connections.sync.SyncItem;
  66. import org.netbeans.modules.php.project.connections.transfer.TransferFile;
  67. import org.openide.DialogDescriptor;
  68. import org.openide.DialogDisplayer;
  69. import org.openide.NotificationLineSupport;
  70. import org.openide.awt.Mnemonics;
  71. import org.openide.filesystems.FileObject;
  72. import org.openide.filesystems.FileUtil;
  73. import org.openide.util.Mutex;
  74. import org.openide.util.NbBundle;
  75. import org.openide.util.RequestProcessor;
  76. /**
  77. * Panel for viewing diffs between remote and local files.
  78. */
  79. public final class DiffPanel extends JPanel {
  80. private static final long serialVersionUID = 54678645646768L;
  81. static final Logger LOGGER = Logger.getLogger(DiffPanel.class.getName());
  82. private static final RequestProcessor RP = new RequestProcessor(DiffPanel.class);
  83. final SyncItem syncItem;
  84. final RemoteClient remoteClient;
  85. final String charsetName;
  86. // tmp files
  87. volatile TmpLocalFile remoteTmpFile = null;
  88. volatile TmpLocalFile localTmpFile = null;
  89. volatile EditableTmpLocalFileStreamSource editableTmpLocalFileStreamSource = null;
  90. // @GuardedBy(AWT)
  91. DialogDescriptor descriptor;
  92. // @GuardedBy(AWT)
  93. private NotificationLineSupport notificationLineSupport = null;
  94. public DiffPanel(RemoteClient remoteClient, SyncItem syncItem, String charsetName) {
  95. this.remoteClient = remoteClient;
  96. this.syncItem = syncItem;
  97. this.charsetName = charsetName;
  98. initComponents();
  99. setPreferredSize(new Dimension(600, 450));
  100. }
  101. @NbBundle.Messages({
  102. "# {0} - file path",
  103. "DiffPanel.title=Remote Diff for {0}",
  104. "DiffPanel.button.titleWithMnemonics=&Take Over Local Changes"
  105. })
  106. public boolean open() throws IOException {
  107. assert SwingUtilities.isEventDispatchThread();
  108. JButton okButton = new JButton();
  109. Mnemonics.setLocalizedText(okButton, Bundle.DiffPanel_button_titleWithMnemonics());
  110. descriptor = new DialogDescriptor(
  111. this,
  112. Bundle.DiffPanel_title(syncItem.getPath()),
  113. true,
  114. new Object[] {okButton, DialogDescriptor.CANCEL_OPTION},
  115. okButton,
  116. DialogDescriptor.DEFAULT_ALIGN,
  117. null,
  118. null);
  119. notificationLineSupport = descriptor.createNotificationLineSupport();
  120. descriptor.setValid(false);
  121. Dialog dialog = DialogDisplayer.getDefault().createDialog(descriptor);
  122. setDiffView();
  123. try {
  124. dialog.setVisible(true);
  125. } finally {
  126. dialog.dispose();
  127. DiffFileEncodingQueryImpl.clear();
  128. }
  129. boolean ok = descriptor.getValue() == okButton;
  130. boolean fileModified = false;
  131. try {
  132. if (editableTmpLocalFileStreamSource != null) {
  133. fileModified = editableTmpLocalFileStreamSource.save();
  134. }
  135. } finally {
  136. if (ok) {
  137. // set new tmp file?
  138. if (fileModified) {
  139. // clean any old tmp file
  140. syncItem.cleanupTmpLocalFile();
  141. // set new tmp file
  142. syncItem.setTmpLocalFile(localTmpFile);
  143. } else {
  144. localTmpFile.cleanup();
  145. }
  146. } else {
  147. // cancel -> cleanup local tmp file
  148. if (localTmpFile != null) {
  149. localTmpFile.cleanup();
  150. }
  151. }
  152. // always cleanup remote tmp file
  153. if (remoteTmpFile != null) {
  154. remoteTmpFile.cleanup();
  155. }
  156. }
  157. return ok;
  158. }
  159. void showError(final String msg) {
  160. Mutex.EVENT.readAccess(new Runnable() {
  161. @Override
  162. public void run() {
  163. if (msg != null) {
  164. notificationLineSupport.setErrorMessage(msg);
  165. descriptor.setValid(false);
  166. } else {
  167. notificationLineSupport.clearMessages();
  168. descriptor.setValid(true);
  169. }
  170. }
  171. });
  172. }
  173. @NbBundle.Messages("DiffPanel.error.cannotReadFiles=Cannot read files for comparison.")
  174. private void setDiffView() {
  175. RP.post(new Runnable() {
  176. @Override
  177. public void run() {
  178. String name = syncItem.getName();
  179. String mimeType = getMimeType();
  180. // remote stream
  181. final StreamSource remoteStream = getRemoteStreamSource(name, mimeType);
  182. if (remoteStream == null) {
  183. // some error, already processed
  184. return;
  185. }
  186. // local stream
  187. editableTmpLocalFileStreamSource = getLocalStreamSource(name, mimeType);
  188. if (editableTmpLocalFileStreamSource == null) {
  189. // some error, already processed
  190. return;
  191. }
  192. // update ui
  193. SwingUtilities.invokeLater(new Runnable() {
  194. @Override
  195. public void run() {
  196. try {
  197. DiffController diffController = DiffController.createEnhanced(remoteStream, editableTmpLocalFileStreamSource);
  198. remove(loadingLabel);
  199. add(diffController.getJComponent(), BorderLayout.CENTER);
  200. revalidate();
  201. repaint();
  202. descriptor.setValid(true);
  203. } catch (IOException ex) {
  204. LOGGER.log(Level.INFO, null, ex);
  205. showError(Bundle.DiffPanel_error_cannotReadFiles());
  206. }
  207. }
  208. });
  209. }
  210. });
  211. }
  212. String getMimeType() {
  213. TransferFile localTransferFile = syncItem.getLocalTransferFile();
  214. if (localTransferFile != null) {
  215. FileObject fileObject = FileUtil.toFileObject(localTransferFile.resolveLocalFile());
  216. if (fileObject != null) {
  217. return fileObject.getMIMEType();
  218. }
  219. }
  220. return getMimeType(syncItem.getName());
  221. }
  222. private String getMimeType(String filename) {
  223. try {
  224. return FileUtil.createMemoryFileSystem().getRoot().createData(filename).getMIMEType();
  225. } catch (IOException ex) {
  226. // ignored, should not happen
  227. LOGGER.log(Level.WARNING, null, ex);
  228. }
  229. return "content/unknown"; // NOI18N
  230. }
  231. @NbBundle.Messages({
  232. "# {0} - file name",
  233. "DiffPanel.error.cannotDownload=File {0} cannot be downloaded."
  234. })
  235. StreamSource getRemoteStreamSource(String name, String mimeType) {
  236. TransferFile transferFile = syncItem.getRemoteTransferFile();
  237. if (transferFile == null) {
  238. return new NullStreamSource(name, mimeType, true);
  239. }
  240. remoteTmpFile = TmpLocalFile.onDisk(getExtension(name));
  241. try {
  242. if (remoteClient.downloadTemporary(remoteTmpFile, transferFile)) {
  243. rememberEncoding(remoteTmpFile);
  244. return new TmpLocalFileStreamSource(name, remoteTmpFile, mimeType, charsetName, true);
  245. } else {
  246. showError(Bundle.DiffPanel_error_cannotDownload(name));
  247. }
  248. } catch (RemoteException ex) {
  249. LOGGER.log(Level.INFO, null, ex);
  250. showError(ex.getLocalizedMessage());
  251. }
  252. return null;
  253. }
  254. @NbBundle.Messages({
  255. "DiffPanel.error.copyContent=Content of file cannot be copied to temporary file.",
  256. "DiffPanel.error.opening=Local file cannot be opened."
  257. })
  258. EditableTmpLocalFileStreamSource getLocalStreamSource(String name, String mimeType) {
  259. localTmpFile = TmpLocalFile.onDisk(getExtension(name));
  260. try {
  261. TmpLocalFile currentTmpLocalFile = syncItem.getTmpLocalFile();
  262. if (currentTmpLocalFile != null) {
  263. // already has tmp file
  264. copyContent(new File(currentTmpLocalFile.getAbsolutePath()), localTmpFile);
  265. } else {
  266. // no tmp file yet
  267. TransferFile localTransferFile = syncItem.getLocalTransferFile();
  268. if (localTransferFile != null) {
  269. copyContent(localTransferFile.resolveLocalFile(), localTmpFile);
  270. }
  271. }
  272. } catch (IOException ex) {
  273. LOGGER.log(Level.WARNING, null, ex);
  274. showError(Bundle.DiffPanel_error_copyContent());
  275. return null;
  276. }
  277. try {
  278. rememberEncoding(localTmpFile);
  279. return new EditableTmpLocalFileStreamSource(name, localTmpFile, mimeType, charsetName, false);
  280. } catch (IOException ex) {
  281. LOGGER.log(Level.WARNING, null, ex);
  282. showError(Bundle.DiffPanel_error_opening());
  283. }
  284. return null;
  285. }
  286. private String getExtension(String filename) {
  287. List<String> parts = StringUtils.explode(filename, "."); // NOI18N
  288. if (parts.isEmpty()) {
  289. return null;
  290. }
  291. return parts.get(parts.size() - 1);
  292. }
  293. private void copyContent(File file, TmpLocalFile localTmpFile) throws IOException {
  294. FileObject fileObject = FileUtil.toFileObject(file);
  295. if (fileObject == null || !fileObject.isValid()) {
  296. return;
  297. }
  298. InputStream inputStream = fileObject.getInputStream();
  299. try {
  300. OutputStream outputStream = localTmpFile.getOutputStream();
  301. try {
  302. FileUtil.copy(inputStream, outputStream);
  303. } finally {
  304. outputStream.close();
  305. }
  306. } finally {
  307. inputStream.close();
  308. }
  309. }
  310. void rememberEncoding(TmpLocalFile tmpLocalFile) {
  311. if (tmpLocalFile != null) {
  312. String path = tmpLocalFile.getAbsolutePath();
  313. assert path != null : "Path for local tmp file should be present";
  314. FileObject fo = FileUtil.toFileObject(new File(path));
  315. assert fo != null : "Fileobject for " + path + " should exist";
  316. DiffFileEncodingQueryImpl.addCharset(fo, Charset.forName(charsetName));
  317. }
  318. }
  319. /**
  320. * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form
  321. * Editor.
  322. */
  323. @SuppressWarnings("unchecked")
  324. // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  325. private void initComponents() {
  326. loadingLabel = new JLabel();
  327. setLayout(new BorderLayout());
  328. loadingLabel.setHorizontalAlignment(SwingConstants.CENTER);
  329. Mnemonics.setLocalizedText(loadingLabel, NbBundle.getMessage(DiffPanel.class, "DiffPanel.loadingLabel.text")); // NOI18N
  330. add(loadingLabel, java.awt.BorderLayout.CENTER);
  331. add(loadingLabel, BorderLayout.CENTER);
  332. }// </editor-fold>//GEN-END:initComponents
  333. // Variables declaration - do not modify//GEN-BEGIN:variables
  334. private JLabel loadingLabel;
  335. // End of variables declaration//GEN-END:variables
  336. }