Java tutorial
/* * Sweeper - Duplicate file cleaner * Copyright (C) 2012 Bogdan Ciprian Pistol * * This program 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 * (at your option) any later version. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package gg.pistol.sweeper.gui; import com.google.common.base.Preconditions; import gg.pistol.sweeper.core.Sweeper; import gg.pistol.sweeper.core.SweeperCount; import gg.pistol.sweeper.core.SweeperPoll; import gg.pistol.sweeper.core.Target; import gg.pistol.sweeper.gui.component.ConfirmationDialog; import gg.pistol.sweeper.i18n.I18n; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import javax.annotation.Nullable; import javax.swing.*; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import java.awt.*; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; // package private class PollPage extends WizardPage { private final WizardPage analysisPage; private final List<Target> targets; @Nullable private JLabel statDelete; @Nullable private AbstractTableModel tableModel; PollPage(WizardPage analysisPage, I18n i18n, WizardPageListener listener, Sweeper sweeper) { super(Preconditions.checkNotNull(i18n), Preconditions.checkNotNull(listener), Preconditions.checkNotNull(sweeper)); Preconditions.checkNotNull(analysisPage); this.analysisPage = analysisPage; targets = new ArrayList<Target>(sweeper.getCurrentPoll().getTargets()); } @Override protected void addComponents(JPanel contentPanel) { Preconditions.checkNotNull(contentPanel); super.addComponents(contentPanel); SweeperCount count = sweeper.getCount(); contentPanel.add(alignLeft(createWordWrappingLabel(i18n.getString(I18n.PAGE_POLL_DESCRIPTION_ID, formatInt(count.getTotalTargets()), formatSize(count.getTotalSize()), formatInt(count.getDuplicateTargets()), formatSize(count.getDuplicateSize()))))); contentPanel.add(createVerticalStrut(20)); JPanel topTablePanel = createHorizontalPanel(); JPanel topLinkPanel = createVerticalPanel(); topLinkPanel.add(createLink(i18n.getString(I18n.PAGE_POLL_LINK_DECIDE_LATER_ALL_ID), markAllAction(SweeperPoll.Mark.DECIDE_LATER))); topLinkPanel.add(createVerticalStrut(3)); topLinkPanel.add( createLink(i18n.getString(I18n.PAGE_POLL_LINK_RETAIN_ALL), markAllAction(SweeperPoll.Mark.RETAIN))); topLinkPanel.add(createVerticalStrut(3)); topLinkPanel.add(createLink(i18n.getString(I18n.PAGE_POLL_LINK_DELETE_ALL_ID), markAllAction(SweeperPoll.Mark.DELETE))); topTablePanel.add(topLinkPanel); topTablePanel.add(Box.createHorizontalGlue()); topTablePanel.add(new JLabel( i18n.getString(I18n.PAGE_POLL_NUMBER_ID, Integer.toString(sweeper.getCurrentPoll().getNumber())))); contentPanel.add(alignLeft(topTablePanel)); contentPanel.add(createVerticalStrut(5)); contentPanel.add(alignLeft(addScrollPane(createTable()))); contentPanel.add(createVerticalStrut(5)); statDelete = createWordWrappingLabel(i18n.getString(I18n.PAGE_POLL_STAT_DELETE_ID, formatInt(count.getToDeleteTargets()), formatSize(count.getToDeleteSize()))); contentPanel.add(alignLeft(statDelete)); contentPanel.add(createVerticalStrut(15)); } private Runnable markAllAction(final SweeperPoll.Mark mark) { return new Runnable() { @Override public void run() { markAllAction0(mark); } }; } private void markAllAction0(SweeperPoll.Mark mark) { for (Target t : targets) { sweeper.getCurrentPoll().mark(t, mark); } /* * The statistics about targets are computed when advancing to the next poll, in this way the Sweeper * implementation knows that the user made a decision for all the targets in the current poll. * But we would like to provide real time statistics, whenever the user marks a target the statistics * should change to reflect that and not wait until the user marked all the targets and advanced to * the next poll. To simulate this we advance to the next poll and back and we have access to * the statistics while the user's perception about the current poll is not changed. */ sweeper.nextPoll(); sweeper.previousPoll(); statDelete.setText( i18n.getString(I18n.PAGE_POLL_STAT_DELETE_ID, formatInt(sweeper.getCount().getToDeleteTargets()), formatSize(sweeper.getCount().getToDeleteSize()))); tableModel.fireTableDataChanged(); } private JTable createTable() { tableModel = createTableModel(); JTable table = new JTable(tableModel) { @Override public String getToolTipText(MouseEvent e) { /* * Have a tooltip for the filename field only and the value of the tooltip will be the full filename. */ String tooltip = null; Point p = e.getPoint(); int rowIndex = rowAtPoint(p); int colIndex = columnAtPoint(p); int realColumnIndex = convertColumnIndexToModel(colIndex); if (isFilenameColumnNo(realColumnIndex)) { tooltip = getValueAt(rowIndex, colIndex).toString(); } return tooltip; } }; table.getTableHeader().setReorderingAllowed(false); final TableCellRenderer booleanRenderer = table.getDefaultRenderer(Boolean.class); final TableCellRenderer stringRenderer = table.getDefaultRenderer(String.class); table.setDefaultRenderer(Boolean.class, new DefaultTableCellRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { return booleanRenderer.getTableCellRendererComponent(table, value, false, false, row, column); } }); table.setDefaultRenderer(String.class, new DefaultTableCellRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { return stringRenderer.getTableCellRendererComponent(table, value, false, false, row, column); } }); for (int column = 0; column < table.getColumnCount(); column++) { packColumn(table, column, isFilenameColumnNo(column)); } table.setComponentOrientation(ComponentOrientation.getOrientation(i18n.getLocale())); return table; } private boolean isFilenameColumnNo(int columnNo) { return columnNo == 3; } private void packColumn(JTable table, int column, boolean autoResize) { TableColumn tableColumn = table.getColumnModel().getColumn(column); TableCellRenderer renderer = table.getTableHeader().getDefaultRenderer(); Component rendererComponent = renderer.getTableCellRendererComponent(table, tableColumn.getHeaderValue(), false, false, -1, column); int width = rendererComponent.getPreferredSize().width; for (int row = 0; row < table.getRowCount(); row++) { renderer = table.getCellRenderer(row, column); rendererComponent = renderer.getTableCellRendererComponent(table, table.getValueAt(row, column), false, false, row, column); width = Math.max(width, rendererComponent.getPreferredSize().width); } width += 6; table.getColumnModel().getColumn(column).setPreferredWidth(width); if (!autoResize) { table.getColumnModel().getColumn(column).setMinWidth(width); table.getColumnModel().getColumn(column).setMaxWidth(width); } } private AbstractTableModel createTableModel() { return new AbstractTableModel() { @Override public int getRowCount() { return targets.size(); } @Override public int getColumnCount() { return 7; } @Override public Object getValueAt(int rowIndex, int columnIndex) { switch (columnIndex) { case 0: return sweeper.getCurrentPoll().getMark(targets.get(rowIndex)) == SweeperPoll.Mark.DECIDE_LATER; case 1: return sweeper.getCurrentPoll().getMark(targets.get(rowIndex)) == SweeperPoll.Mark.RETAIN; case 2: return sweeper.getCurrentPoll().getMark(targets.get(rowIndex)) == SweeperPoll.Mark.DELETE; case 3: return targets.get(rowIndex).getName(); case 4: if (targets.get(rowIndex).getType() == Target.Type.FILE) { return i18n.getString(I18n.RESOURCE_TYPE_FILE_ID); } else { return i18n.getString(I18n.RESOURCE_TYPE_DIRECTORY_ID); } case 5: return formatSize(targets.get(rowIndex).getSize()); case 6: DateTime date = targets.get(rowIndex).getModificationDate(); return date == null ? i18n.getString(I18n.PAGE_POLL_TABLE_COLUMN_DATE_UNKNOWN_ID) : date.toString(DateTimeFormat.patternForStyle("MM", i18n.getLocale())); } return null; } @Override public String getColumnName(int column) { switch (column) { case 0: return i18n.getString(I18n.PAGE_POLL_TABLE_COLUMN_DECIDE_LATER_ID); case 1: return i18n.getString(I18n.PAGE_POLL_TABLE_COLUMN_RETAIN_ID); case 2: return i18n.getString(I18n.PAGE_POLL_TABLE_COLUMN_DELETE_ID); case 3: return i18n.getString(I18n.RESOURCE_NAME_ID); case 4: return i18n.getString(I18n.PAGE_POLL_TABLE_COLUMN_TYPE_ID); case 5: return i18n.getString(I18n.RESOURCE_SIZE_ID); case 6: return i18n.getString(I18n.RESOURCE_MODIFIED_ID); } return null; } @Override public Class<?> getColumnClass(int columnIndex) { return columnIndex < 3 ? Boolean.class : String.class; } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return columnIndex < 3; } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { SweeperPoll.Mark mark = null; switch (columnIndex) { case 0: mark = SweeperPoll.Mark.DECIDE_LATER; break; case 1: mark = SweeperPoll.Mark.RETAIN; break; case 2: mark = SweeperPoll.Mark.DELETE; break; } sweeper.getCurrentPoll().mark(targets.get(rowIndex), mark); // Go to the next poll and back to update the statistics. sweeper.nextPoll(); sweeper.previousPoll(); statDelete.setText(i18n.getString(I18n.PAGE_POLL_STAT_DELETE_ID, formatInt(sweeper.getCount().getToDeleteTargets()), formatSize(sweeper.getCount().getToDeleteSize()))); fireTableRowsUpdated(rowIndex, rowIndex); } }; } private String formatSize(long size) { int gb = (int) (size >> 30); int mb = (int) (size >> 20 & 0x3FF); int kb = (int) (size >> 10 & 0x3FF); int bytes = (int) (size & 0x3FF); if (gb > 0) { return i18n.getString(I18n.SIZE_DESCRIPTION_GB_ID, formatInt(gb), formatInt(mb)); } if (mb > 0) { return i18n.getString(I18n.SIZE_DESCRIPTION_MB_ID, formatInt(mb)); } if (kb > 0) { return i18n.getString(I18n.SIZE_DESCRIPTION_KB_ID, formatInt(kb)); } return i18n.getString(I18n.SIZE_DESCRIPTION_BYTE_ID, formatInt(bytes)); } private String formatInt(int val) { return String.format(i18n.getLocale(), "%1$,d", val); } @Override protected String getPageHeader() { return i18n.getString(I18n.PAGE_POLL_HEADER_ID); } @Override boolean isCancelButtonVisible() { return false; } @Override boolean isCancelButtonEnabled() { return false; } @Override boolean isBackButtonEnabled() { return true; } @Override boolean isNextButtonEnabled() { return true; } @Override boolean isFinishButtonEnabled() { return true; } @Override boolean isLastPage() { return false; } @Override boolean isLanguageSelectorVisible() { return true; } @Override void cancel() { } @Override @Nullable WizardPage back() { if (sweeper.previousPoll() == null) { if (new ConfirmationDialog(getParentWindow(), i18n, i18n.getString(I18n.LABEL_CONFIRMATION_ID), i18n.getString(I18n.PAGE_POLL_BACK_CONFIRMATION_MESSAGE_ID)).isConfirmed()) { setParentWindow(null); return analysisPage; } else { return null; } } PollPage page = new PollPage(analysisPage, i18n, listener, sweeper); page.setParentWindow(getParentWindow()); setParentWindow(null); return page; } @Override WizardPage next() { WizardPage page; if (sweeper.nextPoll() != null) { page = new PollPage(analysisPage, i18n, listener, sweeper); page.setParentWindow(getParentWindow()); setParentWindow(null); } else { page = null; // setParentWindow(null); } return page; } @Override WizardPage finish() { return null; } }