Java tutorial
/* * Copyright (c) 2015, Marek Nowicki * All rights reserved. * * This file is distributable under the Simplified BSD license. See the terms * of the Simplified BSD license in the documentation provided with this file. */ package pl.umk.mat.faramir.beamer; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.HeadlessException; import java.awt.KeyEventDispatcher; import java.awt.KeyboardFocusManager; import java.awt.Toolkit; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.StringReader; import java.nio.charset.Charset; import java.nio.file.Paths; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.filechooser.FileNameExtensionFilter; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.rendering.ImageType; /** * * @author faramir */ public class MainFrame extends javax.swing.JFrame implements KeyEventDispatcher { private final Map<Integer, BufferedImage> presentationMap = new ConcurrentHashMap<>(); private final Map<Integer, SlideNote> notesMap = new LinkedHashMap<>(); private final long doubleClickTime; private final String endSlideString = "--- end slide ---"; private final Pattern pattern = Pattern .compile(endSlideString + "(?:[ ]*(?<sign>\\+?)(?<time>(?:[0-9]+:)?(?:[0-9]+)))?"); private NotesFrame notesFrame; private FullscreenWindow fullscreenWindow; private Thread loadPdfThread; private File presentationFile; private File notesFile; private int currentPage; private int pagesCount; private LocalDateTime startTime; private long lastBlankClicked = System.nanoTime(); /** * Creates new form MainFrame */ public MainFrame() { initComponents(); Object doubleClick = Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval"); if (doubleClick == null || !(doubleClick instanceof Integer)) { doubleClickTime = 330_000_000; } else { doubleClickTime = ((Integer) doubleClick).longValue() * 1_000_000L; } presentationScreenRefreshButtonActionPerformed(null); notesScreenRefreshButtonActionPerformed(null); } /** * 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. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { openFileChooser = new JFileChooser() { @Override public void approveSelection() { if (getSelectedFile().exists()) { super.approveSelection(); } else { JOptionPane.showMessageDialog(this, String.format("Podany plik nie istnieje:\n%s", this.getSelectedFile()), "Plik nie istnieje", JOptionPane.ERROR_MESSAGE); } } }; presentationPanel = new javax.swing.JPanel(); presentationFileLabel = new javax.swing.JLabel(); presentationFileTextField = new javax.swing.JTextField(); presentationScreenLabel = new javax.swing.JLabel(); presentationScreenComboBox = new javax.swing.JComboBox<ScreenDevice>(); presentationLoadingProgressBar = new javax.swing.JProgressBar(); presentationScreenRefreshButton = new javax.swing.JButton(); notesPanel = new javax.swing.JPanel(); notesFileLabel = new javax.swing.JLabel(); notesFileTextField = new javax.swing.JTextField(); notesScreenLabel = new javax.swing.JLabel(); notesScreenComboBox = new javax.swing.JComboBox<ScreenDevice>(); notesScreenRefreshButton = new javax.swing.JButton(); startPresentationButton = new javax.swing.JButton(); FormListener formListener = new FormListener(); openFileChooser.setCurrentDirectory(null); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle("Beamer Presenter"); setLocationByPlatform(true); setResizable(false); presentationPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Prezentacja")); presentationFileLabel.setText("Plik:"); presentationFileTextField.setEditable(false); presentationFileTextField.addMouseListener(formListener); presentationScreenLabel.setText("Monitor:"); presentationScreenComboBox.addItemListener(formListener); presentationLoadingProgressBar.setString("0/0"); presentationScreenRefreshButton.setText("Odwie"); presentationScreenRefreshButton.addActionListener(formListener); javax.swing.GroupLayout presentationPanelLayout = new javax.swing.GroupLayout(presentationPanel); presentationPanel.setLayout(presentationPanelLayout); presentationPanelLayout.setHorizontalGroup(presentationPanelLayout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(presentationPanelLayout.createSequentialGroup().addContainerGap() .addGroup(presentationPanelLayout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(presentationLoadingProgressBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(presentationPanelLayout.createSequentialGroup() .addGroup(presentationPanelLayout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(presentationScreenLabel) .addComponent(presentationFileLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(presentationPanelLayout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(presentationFileTextField) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, presentationPanelLayout.createSequentialGroup() .addComponent(presentationScreenComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap( javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(presentationScreenRefreshButton, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE))))) .addContainerGap())); presentationPanelLayout.setVerticalGroup(presentationPanelLayout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(presentationPanelLayout.createSequentialGroup().addGroup(presentationPanelLayout .createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(presentationFileLabel).addComponent(presentationFileTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(presentationPanelLayout .createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(presentationScreenLabel) .addComponent(presentationScreenComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(presentationScreenRefreshButton)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(presentationLoadingProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap())); notesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Notatki")); notesFileLabel.setText("Plik:"); notesFileTextField.setEditable(false); notesFileTextField.addMouseListener(formListener); notesScreenLabel.setText("Monitor:"); notesScreenRefreshButton.setText("Odwie"); notesScreenRefreshButton.setName(""); // NOI18N notesScreenRefreshButton.addActionListener(formListener); javax.swing.GroupLayout notesPanelLayout = new javax.swing.GroupLayout(notesPanel); notesPanel.setLayout(notesPanelLayout); notesPanelLayout.setHorizontalGroup(notesPanelLayout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(notesPanelLayout.createSequentialGroup().addContainerGap() .addGroup(notesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(notesScreenLabel).addComponent(notesFileLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(notesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(notesFileTextField) .addGroup(notesPanelLayout.createSequentialGroup() .addComponent(notesScreenComboBox, 0, 334, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(notesScreenRefreshButton, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE))) .addContainerGap())); notesPanelLayout.setVerticalGroup(notesPanelLayout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(notesPanelLayout.createSequentialGroup() .addGroup(notesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(notesFileLabel).addComponent(notesFileTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(notesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(notesScreenLabel) .addComponent(notesScreenComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(notesScreenRefreshButton)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))); startPresentationButton.setText("Rozpocznij prezentacj"); startPresentationButton.setEnabled(false); startPresentationButton.addActionListener(formListener); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup().addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(presentationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(notesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(startPresentationButton, 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().addContainerGap() .addComponent(presentationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(notesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(startPresentationButton).addContainerGap())); pack(); } // Code for dispatching events from components to event handlers. private class FormListener implements java.awt.event.ActionListener, java.awt.event.ItemListener, java.awt.event.MouseListener { FormListener() { } public void actionPerformed(java.awt.event.ActionEvent evt) { if (evt.getSource() == presentationScreenRefreshButton) { MainFrame.this.presentationScreenRefreshButtonActionPerformed(evt); } else if (evt.getSource() == notesScreenRefreshButton) { MainFrame.this.notesScreenRefreshButtonActionPerformed(evt); } else if (evt.getSource() == startPresentationButton) { MainFrame.this.startPresentationButtonActionPerformed(evt); } } public void itemStateChanged(java.awt.event.ItemEvent evt) { if (evt.getSource() == presentationScreenComboBox) { MainFrame.this.presentationScreenComboBoxItemStateChanged(evt); } } public void mouseClicked(java.awt.event.MouseEvent evt) { if (evt.getSource() == presentationFileTextField) { MainFrame.this.presentationFileMouseClicked(evt); } else if (evt.getSource() == notesFileTextField) { MainFrame.this.notesFileTextFieldMouseClicked(evt); } } public void mouseEntered(java.awt.event.MouseEvent evt) { } public void mouseExited(java.awt.event.MouseEvent evt) { } public void mousePressed(java.awt.event.MouseEvent evt) { } public void mouseReleased(java.awt.event.MouseEvent evt) { } }// </editor-fold>//GEN-END:initComponents @Override public boolean dispatchKeyEvent(KeyEvent e) { if (openFileChooser.isShowing()) { return false; } if (e.getID() == KeyEvent.KEY_PRESSED) { if (e.getKeyCode() == KeyEvent.VK_F5) { startPresentationButtonActionPerformed(null); } /** * Prezenter: PG UP, PG DOWN, PERIOD ('.'), (F5, Escape) */ switch (e.getKeyCode()) { case KeyEvent.VK_PERIOD: if (notesFrame != null) { if (System.nanoTime() - lastBlankClicked < doubleClickTime) { notesFrame.clearTime(); } } lastBlankClicked = System.nanoTime(); return true; case KeyEvent.VK_ESCAPE: if (fullscreenWindow != null) { fullscreenWindow.dispose(); fullscreenWindow = null; } if (notesFrame != null) { if (notesFrame.isUndecorated()) { notesFrame.dispose(); notesFrame = null; } } return true; case KeyEvent.VK_ENTER: case KeyEvent.VK_PAGE_DOWN: case KeyEvent.VK_DOWN: case KeyEvent.VK_RIGHT: case KeyEvent.VK_SPACE: if (currentPage + 1 < pagesCount) { ++currentPage; } refreshFullscreenPage(); showTiming(); return true; case KeyEvent.VK_PAGE_UP: case KeyEvent.VK_UP: case KeyEvent.VK_LEFT: if (currentPage - 1 >= 0) { --currentPage; } refreshFullscreenPage(); showTiming(); return true; case KeyEvent.VK_HOME: currentPage = 0; refreshFullscreenPage(); showTiming(); return true; case KeyEvent.VK_END: currentPage = pagesCount - 1; refreshFullscreenPage(); showTiming(); return true; case KeyEvent.VK_R: refreshFullscreenPage(); return true; } } return false; } private void presentationFileMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_presentationFileMouseClicked if (evt.getClickCount() >= 2 && evt.getButton() == MouseEvent.BUTTON1) { openFileChooser.setFileFilter(new FileNameExtensionFilter("PDF files", "pdf")); openFileChooser.setSelectedFile(presentationFile); if (presentationFile == null && notesFile != null) { openFileChooser.setCurrentDirectory(notesFile.getParentFile()); } if (openFileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { presentationFile = openFileChooser.getSelectedFile(); openPresentationFile(); } } }//GEN-LAST:event_presentationFileMouseClicked private void openPresentationFile() throws HeadlessException { presentationFileTextField.setText(presentationFile.getAbsolutePath()); loadPdfFile(); startTime = null; String name = presentationFile.getName().replaceAll("\\.[^.]*$", ".txt"); File guessNotesFile = Paths.get(presentationFile.getParent(), name).toFile(); if (guessNotesFile.canRead()) { notesFile = guessNotesFile; openNotesFile(); } } private void notesFileTextFieldMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_notesFileTextFieldMouseClicked if (evt.getClickCount() >= 2) { if (evt.getButton() != MouseEvent.BUTTON1) { notesFileTextField.setText(""); notesFile = null; notesMap.clear(); } else { openFileChooser.setFileFilter(new FileNameExtensionFilter("TXT files", "txt")); openFileChooser.setSelectedFile(notesFile); if (openFileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { notesFile = openFileChooser.getSelectedFile(); openNotesFile(); } } checkStartPresentationButtonEnabled(); } }//GEN-LAST:event_notesFileTextFieldMouseClicked private void openNotesFile() throws HeadlessException { notesFileTextField.setText(notesFile.getAbsolutePath()); loadTxtFile(); } private void presentationScreenRefreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_presentationScreenRefreshButtonActionPerformed presentationScreenComboBox.removeAllItems(); GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] devices = env.getScreenDevices(); for (GraphicsDevice device : devices) { if (device.isFullScreenSupported()) { presentationScreenComboBox.addItem(new ScreenDevice(device)); } } }//GEN-LAST:event_presentationScreenRefreshButtonActionPerformed private void notesScreenRefreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_notesScreenRefreshButtonActionPerformed notesScreenComboBox.removeAllItems(); GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] devices = env.getScreenDevices(); notesScreenComboBox.addItem(new ScreenDevice(null)); for (GraphicsDevice device : devices) { if (device.isFullScreenSupported()) { notesScreenComboBox.addItem(new ScreenDevice(device)); } } loadTxtFile(); }//GEN-LAST:event_notesScreenRefreshButtonActionPerformed private void presentationScreenComboBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_presentationScreenComboBoxItemStateChanged startPresentationButton.setEnabled(false); loadPdfFile(); }//GEN-LAST:event_presentationScreenComboBoxItemStateChanged private void startPresentationButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startPresentationButtonActionPerformed if (startPresentationButton.isEnabled() == false) { return; } if (startTime == null) { startTime = LocalDateTime.now(); } GraphicsDevice slidesDevice = ((ScreenDevice) presentationScreenComboBox.getSelectedItem()).getDevice(); GraphicsDevice notesDevice = ((ScreenDevice) notesScreenComboBox.getSelectedItem()).getDevice(); if (notesFrame != null) { notesFrame.dispose(); notesFrame = null; } if (notesDevice != null) { boolean fullscreen = notesDevice.getIDstring().equals(slidesDevice.getIDstring()) == false; notesFrame = new NotesFrame(fullscreen, this); if (fullscreen) { notesFrame.setLocation(notesDevice.getDefaultConfiguration().getBounds().x, notesFrame.getY()); } else { notesDevice.setFullScreenWindow(notesFrame); } notesFrame.setVisible(true); } if (fullscreenWindow != null) { fullscreenWindow.dispose(); fullscreenWindow = null; } fullscreenWindow = new FullscreenWindow(this); fullscreenWindow.createWindow(slidesDevice); if (notesFrame != null) { notesFrame.toFront(); } refreshFullscreenPage(); showTiming(); }//GEN-LAST:event_startPresentationButtonActionPerformed private void checkStartPresentationButtonEnabled() { startPresentationButton.setEnabled(presentationMap.isEmpty() == false); } private void loadPdfFile() { if (presentationFile == null) { return; } if (loadPdfThread != null) { loadPdfThread.interrupt(); loadPdfThread = null; } loadPdfThread = new Thread(() -> { try (PDDocument pdfDocument = PDDocument.load(presentationFile)) { PdfRenderer renderer = new PdfRenderer(pdfDocument); ScreenDevice screenDevice = (ScreenDevice) presentationScreenComboBox.getSelectedItem(); GraphicsDevice selectedDevice = screenDevice.getDevice(); pagesCount = pdfDocument.getNumberOfPages(); presentationLoadingProgressBar.setMaximum(pagesCount); presentationLoadingProgressBar.setValue(0); // presentationLoadingProgressBar.setStringPainted(false); presentationMap.clear(); currentPage = 0; for (int processedPage = 0; processedPage < pagesCount; ++processedPage) { presentationLoadingProgressBar.setString(String.format("%d/%d", processedPage, pagesCount)); PDRectangle rect = pdfDocument.getPage(processedPage).getCropBox(); float width = selectedDevice.getDisplayMode().getWidth(); float height = selectedDevice.getDisplayMode().getHeight(); float screenProportion = width / height; float scale; if (screenProportion <= rect.getWidth() / rect.getHeight()) { scale = width / rect.getWidth(); } else { scale = height / rect.getHeight(); } BufferedImage bi = renderer.renderImage(processedPage, scale * 2.0f, ImageType.RGB); if (Thread.interrupted()) { return; } presentationMap.put(processedPage, bi); presentationLoadingProgressBar.setValue(processedPage + 1); checkStartPresentationButtonEnabled(); refreshFullscreenPage(); } presentationLoadingProgressBar.setString(String.format("%d/%d", pagesCount, pagesCount)); } catch (IOException ex) { JOptionPane.showMessageDialog(this, String.format("Wystpi wyjtek:\n%s", ex.getLocalizedMessage()), "Bd", JOptionPane.ERROR_MESSAGE); } }); loadPdfThread.start(); } private String trimToString(StringBuilder sb) { int begin; for (begin = 0; begin < sb.length(); ++begin) { if (!Character.isWhitespace(sb.charAt(begin))) { break; } } int end; for (end = sb.length() - 1; end > begin; --end) { if (!Character.isWhitespace(sb.charAt(end))) { break; } } return sb.substring(begin, end + 1); } private void loadTxtFile() throws HeadlessException { notesMap.clear(); if (notesFile == null) { return; } int page = 0; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (BufferedInputStream input = new BufferedInputStream(new FileInputStream(notesFile))) { byte[] buf = new byte[1024]; int len; while ((len = input.read(buf)) != -1) { baos.write(buf, 0, len); } } byte[] bytes = baos.toByteArray(); Charset charset = CharsetDetector.detectCharset(bytes); try (BufferedReader br = new BufferedReader(new StringReader(new String(bytes, charset)))) { String line; StringBuilder sb = new StringBuilder(); long time = 0; do { line = br.readLine(); if (line == null || line.startsWith(endSlideString)) { if (line != null) { try { Matcher matcher = pattern.matcher(line); if (matcher.matches() && matcher.groupCount() > 0) { String signStr = matcher.group("sign"); boolean sign = (signStr != null && "+".equals(signStr)); String timeStr = matcher.group("time"); if (timeStr != null) { if (timeStr.contains(":")) { String[] timeSplit = timeStr.split(":"); time = (sign ? time : 0L) + 60L * Integer.parseInt(timeSplit[0]) + Integer.parseInt(timeSplit[1]); } else { time = (sign ? time : 0L) + Integer.parseInt(timeStr); } } } } catch (Exception ex) { JOptionPane.showMessageDialog(this, String.format("Wystpi wyjtek:\n%s", ex.getLocalizedMessage()), "Bd", JOptionPane.ERROR_MESSAGE); } } SlideNote note = new SlideNote(trimToString(sb), time); System.out.println("Note: " + note); notesMap.put(page++, note); sb.setLength(0); } else { sb.append(line).append(System.lineSeparator()); } } while (line != null); } } catch (IOException ex) { JOptionPane.showMessageDialog(this, String.format("Wystpi wyjtek:\n%s", ex.getLocalizedMessage()), "Bd", JOptionPane.ERROR_MESSAGE); } } private void refreshFullscreenPage() { if (fullscreenWindow != null) { fullscreenWindow.drawOnCenter(presentationMap.get(currentPage)); } if (notesFrame != null) { long previousStart = 0; SlideNote previousNote = notesMap.get(currentPage - 1); if (previousNote != null) { previousStart = previousNote.getSeconds(); } notesFrame.changeSlideInfo(currentPage + 1, pagesCount, notesMap.get(currentPage), previousStart, presentationMap.get(currentPage), presentationMap.get(currentPage + 1)); } } private void showTiming() { if (fullscreenWindow != null || notesFrame != null) { LocalDateTime now = LocalDateTime.now();//.truncatedTo(ChronoUnit.SECONDS); long elapsedMillis = ChronoUnit.MILLIS.between(getStartTime(), now); System.out.printf("Slide %d/%d: %.1f%n", currentPage + 1, pagesCount, elapsedMillis / 1e3); } } public static void main(String args[]) { try { javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) { java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } MainFrame mainFrame = new MainFrame(); KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(mainFrame); if (args.length > 0) { try { mainFrame.presentationFile = Paths.get(args[0]).toFile(); mainFrame.openPresentationFile(); if (args.length > 1) { mainFrame.notesFile = Paths.get(args[1]).toFile(); mainFrame.openNotesFile(); } } catch (Exception ex) { ex.printStackTrace(System.err); } } java.awt.EventQueue.invokeLater(() -> mainFrame.setVisible(true)); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel notesFileLabel; private javax.swing.JTextField notesFileTextField; private javax.swing.JPanel notesPanel; private javax.swing.JComboBox<ScreenDevice> notesScreenComboBox; private javax.swing.JLabel notesScreenLabel; private javax.swing.JButton notesScreenRefreshButton; private javax.swing.JFileChooser openFileChooser; private javax.swing.JLabel presentationFileLabel; private javax.swing.JTextField presentationFileTextField; private javax.swing.JProgressBar presentationLoadingProgressBar; private javax.swing.JPanel presentationPanel; private javax.swing.JComboBox<ScreenDevice> presentationScreenComboBox; private javax.swing.JLabel presentationScreenLabel; private javax.swing.JButton presentationScreenRefreshButton; private javax.swing.JButton startPresentationButton; // End of variables declaration//GEN-END:variables public LocalDateTime getStartTime() { if (startTime == null) { return LocalDateTime.now();//.truncatedTo(ChronoUnit.SECONDS); } else { return startTime; } } public void setStartTime(LocalDateTime startTime) { if (startTime == null) { this.startTime = null; } else { this.startTime = startTime;//.truncatedTo(ChronoUnit.SECONDS); } } // private Charset detectCharset(byte[] bytes, String[] charsets) throws IOException, CharacterCodingException { // for (String charsetName : charsets) { // Charset charset = Charset.forName(charsetName); // // CharsetDecoder decoder = charset.newDecoder() // .onUnmappableCharacter(CodingErrorAction.REPORT) // .onMalformedInput(CodingErrorAction.REPORT); // // try { // decoder.decode(ByteBuffer.wrap(bytes)); // return charset; // } catch (CharacterCodingException ex) { // } // } // throw new CharacterCodingException(); // } }