Java tutorial
/* * Copyright 2015 Patrik Karlsson. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package se.trixon.toolbox.checksum; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.nio.file.FileVisitOption; import java.nio.file.Files; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.concurrent.TimeUnit; import javax.swing.DefaultComboBoxModel; import javax.swing.JFileChooser; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemUtils; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.netbeans.api.settings.ConvertAsProperties; import org.openide.awt.StatusDisplayer; import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.RequestProcessor; import org.openide.util.TaskListener; import org.openide.windows.TopComponent; import se.trixon.almond.SystemHelper; import se.trixon.almond.dialogs.FileChooserPanel; import se.trixon.almond.dialogs.Message; import se.trixon.almond.dialogs.SimpleDialog; import se.trixon.almond.dictionary.Dict; import se.trixon.almond.icon.Pict; import se.trixon.toolbox.core.Toolbox; import se.trixon.toolbox.core.base.ToolTopComponent; /** * Checksum top component. */ @ConvertAsProperties(dtd = "-//se.trixon.toolbox.checksum//Checksum//EN", autostore = false) @TopComponent.Description(preferredID = "ChecksumTopComponent", //iconBase="SET/PATH/TO/ICON/HERE", persistenceType = TopComponent.PERSISTENCE_ALWAYS) @TopComponent.Registration(mode = "editor", openAtStartup = false) public final class ChecksumTopComponent extends ToolTopComponent implements FileChooserPanel.FileChooserButtonListener { private static final int ICON_SIZE = TOOLBAR_ICON_SIZE; private final ArrayList<ChecksumRow> mChecksumRows = new ArrayList<>(); private final ChecksumController mController; private String mAlgorithm; private File mChecksumFilePrefix; public ChecksumTopComponent() { mBundle = NbBundle.getBundle(ChecksumTopComponent.class); mToolName = mBundle.getString("Tool-Name"); initComponents(); setName(mToolName); mController = new ChecksumController(this); initAlgorithms(); init(); } @Override public void onFileChooserCancel(FileChooserPanel fileChooserPanel) { // nvm } @Override public void onFileChooserCheckBoxChange(FileChooserPanel fileChooserPanel, boolean isSelected) { // nvm } @Override public void onFileChooserDrop(FileChooserPanel fileChooserPanel) { if (fileChooserPanel == sourceChooserPanel) { logPanel.clear(); } } @Override public void onFileChooserOk(FileChooserPanel fileChooserPanel, File file) { JFileChooser fileChooser = fileChooserPanel.getFileChooser(); if (fileChooserPanel == sourceChooserPanel) { logPanel.clear(); if (fileChooser.isMultiSelectionEnabled()) { String paths = StringUtils.join(fileChooser.getSelectedFiles(), SystemUtils.PATH_SEPARATOR); fileChooserPanel.setPath(paths); } } } @Override public void onFileChooserPreSelect(FileChooserPanel fileChooserPanel) { final String[] paths = sourceChooserPanel.getPath().split(SystemUtils.PATH_SEPARATOR); File[] files = new File[paths.length]; for (int i = 0; i < files.length; i++) { files[i] = new File(paths[i]); } sourceChooserPanel.getFileChooser().setSelectedFiles(files); } private void init() { openButton.setIcon(Pict.Actions.DOCUMENT_OPEN.get(ICON_SIZE)); openButton.setToolTipText(Dict.OPEN.getString()); openButton.setVisible(false); saveButton.setIcon(Pict.Actions.DOCUMENT_SAVE.get(ICON_SIZE)); saveButton.setToolTipText(Dict.SAVE_AS.getString()); saveButton.setEnabled(false); clearButton.setIcon(Pict.Actions.EDIT_CLEAR.get(ICON_SIZE)); clearButton.setToolTipText(Dict.CLEAR.getString()); clearButton.setVisible(false); calcButton.setIcon(Pict.Actions.ARROW_RIGHT.get(ICON_SIZE)); calcButton.setToolTipText(Dict.START.getString()); compareButton.setIcon(Pict.Actions.MERGE.get(ICON_SIZE)); compareButton.setToolTipText(Dict.COMPARE.getString()); File file = new File(System.getProperty("user.home"), "checksum.zero"); sourceChooserPanel.setDropMode(FileChooserPanel.DropMode.MULTI); sourceChooserPanel.setPath(file.getAbsolutePath()); sourceChooserPanel.setHeader(Dict.SOURCE.getString()); // sourceChooserPanel.getButton().setVisible(false); sourceChooserPanel.setMode(JFileChooser.FILES_AND_DIRECTORIES); sourceChooserPanel.getFileChooser().setMultiSelectionEnabled(true); sourceChooserPanel.setButtonListener(this); checksumChooserPanel.setHeader(mBundle.getString("checksumChooser.header")); if (SystemUtils.IS_OS_WINDOWS) { algorithmComboBox.setMaximumSize(new Dimension(300, 32767)); } } private void initAlgorithms() { String[] requests = new String[] { "MD2_disable", "MD5", "SHA-1", "SHA-256", "SHA-384", "SHA-512" }; ArrayList<String> algorithms = new ArrayList<>(); for (String algorithm : requests) { try { MessageDigest md = MessageDigest.getInstance(algorithm); algorithms.add(algorithm); } catch (NoSuchAlgorithmException ex) { // nvm } } algorithms.add("CRC32"); Collections.sort(algorithms); String[] array = algorithms.toArray(new String[algorithms.size()]); algorithmComboBox.setModel(new DefaultComboBoxModel(array)); algorithmComboBox.setSelectedItem("MD5"); } private String getRelativePath(File file, File base) { return StringUtils.substringAfter(file.getAbsolutePath(), base.getAbsolutePath() + SystemUtils.FILE_SEPARATOR); } /** * 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 Editor. */ // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { toolBar = new javax.swing.JToolBar(); openButton = new javax.swing.JButton(); clearButton = new javax.swing.JButton(); algorithmComboBox = new javax.swing.JComboBox(); calcButton = new javax.swing.JButton(); saveButton = new javax.swing.JButton(); compareButton = new javax.swing.JButton(); filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 0)); sourceChooserPanel = new se.trixon.almond.dialogs.FileChooserPanel(); checksumChooserPanel = new se.trixon.almond.dialogs.FileChooserPanel(); logPanel = new se.trixon.almond.swing.LogPanel(); toolBar.setFloatable(false); openButton.setFocusable(false); openButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); openButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { openButtonActionPerformed(evt); } }); toolBar.add(openButton); clearButton.setFocusable(false); clearButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); clearButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); clearButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { clearButtonActionPerformed(evt); } }); toolBar.add(clearButton); algorithmComboBox.setToolTipText(org.openide.util.NbBundle.getMessage(ChecksumTopComponent.class, "ChecksumTopComponent.algorithmComboBox.toolTipText")); // NOI18N algorithmComboBox.setMaximumSize(new java.awt.Dimension(200, 32767)); toolBar.add(algorithmComboBox); calcButton.setFocusable(false); calcButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { calcButtonActionPerformed(evt); } }); toolBar.add(calcButton); saveButton.setFocusable(false); saveButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); saveButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); saveButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { saveButtonActionPerformed(evt); } }); toolBar.add(saveButton); compareButton.setFocusable(false); compareButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); compareButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); toolBar.add(compareButton); toolBar.add(filler1); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(toolBar, javax.swing.GroupLayout.DEFAULT_SIZE, 546, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup().addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(sourceChooserPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(checksumChooserPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(logPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap())); layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(toolBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(sourceChooserPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(checksumChooserPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(logPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))); }// </editor-fold>//GEN-END:initComponents private void calcButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_calcButtonActionPerformed logPanel.clear(); new CalculateChecksumAction().actionPerformed(evt); }//GEN-LAST:event_calcButtonActionPerformed private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed logPanel.clear(); }//GEN-LAST:event_clearButtonActionPerformed private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed SimpleDialog.setParent(openButton.getTopLevelAncestor()); if (SimpleDialog.openFileAndDirectoy(true)) { String paths = StringUtils.join(SimpleDialog.getPaths(), SystemUtils.PATH_SEPARATOR); sourceChooserPanel.setPath(paths); logPanel.clear(); } }//GEN-LAST:event_openButtonActionPerformed private void requestFileObject() { SimpleDialog.setParent(this); String fileName = String.format("%s.%s", mChecksumFilePrefix.getAbsolutePath(), mAlgorithm); File file = new File(fileName); SimpleDialog.setPath(file.getParentFile()); SimpleDialog.setSelectedFile(file); if (SimpleDialog.saveFile()) { saveFile(SimpleDialog.getPath()); } } private void saveFile(File file) { Calendar calendar = Calendar.getInstance(); String header = String.format("#Created by %s@%s on %s with TT Checksum, www.trixon.se/toolbox\n", System.getProperty("user.name"), SystemHelper.getHostname(), calendar.getTime()); try { FileUtils.write(file, header); FileUtils.writeLines(file, mChecksumRows, true); FileUtils.writeStringToFile(file, "\n", true); } catch (IOException ex) { Message.error(Dict.IO_ERROR_TITLE.getString(), String.format(Dict.FILE_ERROR_WRITE_MESSAGE.getString(), file.getAbsolutePath())); } } private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveButtonActionPerformed requestFileObject(); }//GEN-LAST:event_saveButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JComboBox algorithmComboBox; private javax.swing.JButton calcButton; private se.trixon.almond.dialogs.FileChooserPanel checksumChooserPanel; private javax.swing.JButton clearButton; private javax.swing.JButton compareButton; private javax.swing.Box.Filler filler1; private se.trixon.almond.swing.LogPanel logPanel; private javax.swing.JButton openButton; private javax.swing.JButton saveButton; private se.trixon.almond.dialogs.FileChooserPanel sourceChooserPanel; private javax.swing.JToolBar toolBar; // End of variables declaration//GEN-END:variables @Override public void componentOpened() { } @Override public void componentClosed() { } void writeProperties(java.util.Properties p) { p.setProperty("version", "1.0"); } void readProperties(java.util.Properties p) { String version = p.getProperty("version"); } class CalculateChecksumAction implements ActionListener { private File mBaseDir = null; private final List<Exception> mExceptions = new ArrayList<>(); private boolean mInterrupted = false; private final List<String> mRelativePaths = new ArrayList<>(); private final RequestProcessor mRequestProcessor = new RequestProcessor("interruptible tasks", 1, true); private String mTextPaths; @Override public void actionPerformed(ActionEvent e) { mChecksumRows.clear(); mTextPaths = sourceChooserPanel.getTextField().getText().trim(); if (mTextPaths.length() == 0) { return; } CalculateRunnable runnable = new CalculateRunnable(); final RequestProcessor.Task task = mRequestProcessor.create(runnable); final ProgressHandle progressHandle = ProgressHandleFactory.createHandle(mToolName, task); task.addTaskListener(new TaskListener() { @Override public void taskFinished(org.openide.util.Task task) { progressHandle.finish(); enableToolbar(true); saveButton.setEnabled(!mChecksumRows.isEmpty() && !mInterrupted); } }); progressHandle.start(); task.schedule(0); } private String calculateFile(File file, String algorithm) throws FileNotFoundException, IOException { String sum = null; InputStream inputStream = null; try { if (!algorithm.equalsIgnoreCase("crc32")) { inputStream = new FileInputStream(file); } switch (algorithm) { case "crc32": sum = String.format("%08x", FileUtils.checksumCRC32(file)); break; case "md2": sum = DigestUtils.md2Hex(inputStream); break; case "md5": sum = DigestUtils.md5Hex(inputStream); break; case "sha1": sum = DigestUtils.sha1Hex(inputStream); break; case "sha256": sum = DigestUtils.sha256Hex(inputStream); break; case "sha384": sum = DigestUtils.sha384Hex(inputStream); break; case "sha512": sum = DigestUtils.sha512Hex(inputStream); break; default: } } catch (FileNotFoundException ex) { throw ex; } catch (IOException ex) { throw ex; } finally { try { if (inputStream != null) { inputStream.close(); } } catch (IOException ex) { throw ex; } } return sum; } private void enableToolbar(boolean state) { openButton.setEnabled(state); saveButton.setEnabled(state); clearButton.setEnabled(state); compareButton.setEnabled(state); calcButton.setEnabled(state); algorithmComboBox.setEnabled(state); } private boolean initFileList() { logPanel.println(Dict.GENERATING_FILELIST.getString()); boolean invalidPath = false; File[] files = sourceChooserPanel.getPaths(); if (files != null) { for (File file : files) { String path = file.getAbsolutePath(); if (path.contains(SystemUtils.PATH_SEPARATOR)) { invalidPath = true; String message = String.format(Dict.INVALID_PATH.getString(), file.getAbsolutePath()); logPanel.println(message); } } if (invalidPath) { String message = String.format(Dict.ERROR_PATH_SEPARATOR.getString(), SystemUtils.PATH_SEPARATOR); Message.error(Dict.IO_ERROR_TITLE.getString(), message); } } final String[] paths = mTextPaths.split(SystemUtils.PATH_SEPARATOR); File file0 = new File(paths[0]); if (paths.length == 1 && file0.isDirectory()) { mBaseDir = file0.getAbsoluteFile(); } else { mBaseDir = file0.getParentFile(); } if (paths.length == 1) { if (file0.isDirectory()) { mChecksumFilePrefix = new File(file0, file0.getName()); } else if (file0.isFile()) { mChecksumFilePrefix = file0.getAbsoluteFile(); } } else { mChecksumFilePrefix = new File(mBaseDir, mBaseDir.getName()); } EnumSet<FileVisitOption> fileVisitOptions = EnumSet.of(FileVisitOption.FOLLOW_LINKS); for (String path : paths) { File file = new File(path); if (file.isDirectory()) { FileVisitor fileVisitor = new FileVisitor(mBaseDir, mRelativePaths); try { Files.walkFileTree(file.toPath(), fileVisitOptions, Integer.MAX_VALUE, fileVisitor); if (fileVisitor.isInterrupted()) { return false; } } catch (IOException ex) { Exceptions.printStackTrace(ex); } } else if (file.isFile()) { mRelativePaths.add(getRelativePath(file, mBaseDir)); } } if (mRelativePaths.isEmpty()) { logPanel.println(Dict.FILELIST_EMPTY.getString()); } else { Collections.sort(mRelativePaths); } // for (String s : mRelativePaths) { // logPanel.println(s); // } return true; } class CalculateRunnable implements Runnable { @Override public void run() { long startTime = System.currentTimeMillis(); enableToolbar(false); mInterrupted = !initFileList(); String status; if (!mInterrupted && !mRelativePaths.isEmpty()) { status = String.format("\n%s\n", mBundle.getString("calculating_checksums")); logPanel.println(status); mAlgorithm = algorithmComboBox.getSelectedItem().toString().toLowerCase().replace("-", ""); for (String relativePath : mRelativePaths) { File file = new File(mBaseDir, relativePath); Toolbox.setStatusText(relativePath, StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); try { String sum = calculateFile(file, mAlgorithm); ChecksumRow checksumRow = new ChecksumRow(sum, relativePath); mChecksumRows.add(checksumRow); logPanel.println(new ChecksumRow(sum, relativePath).toString()); } catch (FileNotFoundException ex) { mExceptions.add(ex); } catch (IOException ex) { mExceptions.add(ex); } if (Thread.interrupted()) { mInterrupted = true; break; } } } if (mInterrupted) { status = Dict.TASK_ABORTED.getString(); } else { for (Exception exception : mExceptions) { logPanel.println(String.format("#%s", exception.getLocalizedMessage())); } long millis = System.currentTimeMillis() - startTime; long min = TimeUnit.MILLISECONDS.toMinutes(millis); long sec = TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)); status = String.format("%s (%d %s, %d %s)", Dict.TASK_COMPLETED.getString(), min, Dict.TIME_MIN.getString(), sec, Dict.TIME_SEC.getString()); } logPanel.println("\n" + status); Toolbox.setStatusText("", StatusDisplayer.IMPORTANCE_ERROR_HIGHLIGHT); } } } }