src/main/java/cz/frantovo/rozsireneatributy/gui/Panel.java
author František Kučera <franta-hg@frantovo.cz>
Sun, 24 Dec 2023 00:38:41 +0100
branchv_0
changeset 42 d2414701ce09
parent 41 64e564c2f069
permissions -rw-r--r--
režimy zamykání:

- vypnuté: tlačítko pro zamykání je skryté a soubor se nezamyká
- volitelné: uživatel může soubor zamknout, ale může editovat i bez toho
- povinné: uživatel musí soubor zamknout, aby mohl atributy editovat

Změny v atributech se vždy propisují okamžitě - na ně zámek nemá vliv.
Zámek je na souboru (ne metadatech) a slouží pro kooperující procesy.
Proces, který soubor/metadata čte, si jednak může soubor zamknout (POSIX)
a tím mít jistotu, že zrovna neprobíhá editace.
A jednak může reagovat na notifikace CLOSE_WRITE (inotify).
Notifikaci mu pošleme tím, že soubor odemkneme (čímž se i zavře).
     1 /**
     2  * Rozšířené atributy – program na správu rozšířených atributů souborů
     3  * Copyright © 2012 František Kučera (frantovo.cz)
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, either version 3 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
    16  */
    17 package cz.frantovo.rozsireneatributy.gui;
    18 
    19 import cz.frantovo.rozsireneatributy.Atribut;
    20 import cz.frantovo.rozsireneatributy.CSV;
    21 import cz.frantovo.rozsireneatributy.Konfigurace;
    22 import java.awt.Toolkit;
    23 import java.awt.datatransfer.StringSelection;
    24 import java.awt.event.KeyEvent;
    25 import java.io.IOException;
    26 import java.io.StringWriter;
    27 import java.util.ResourceBundle;
    28 import java.util.logging.Level;
    29 import java.util.logging.Logger;
    30 import javax.swing.JOptionPane;
    31 import javax.swing.JTable;
    32 import javax.swing.KeyStroke;
    33 import javax.swing.ListSelectionModel;
    34 import javax.swing.event.ListSelectionEvent;
    35 import javax.swing.event.ListSelectionListener;
    36 import javax.swing.table.TableCellEditor;
    37 
    38 /**
    39  * @author Ing. František Kučera (frantovo.cz)
    40  */
    41 public class Panel extends javax.swing.JPanel {
    42 
    43 	public static final int SLOUPEC_NÁZVU = 0;
    44 	public static final int SLOUPEC_HODNOTY = 1;
    45 	private static final Logger log = Logger
    46 		.getLogger(Panel.class.getSimpleName());
    47 	private static final ResourceBundle překlady = ResourceBundle
    48 		.getBundle(Atribut.class.getPackageName() + ".Překlady");
    49 	private Model model;
    50 	private Atribut vybranýAtribut;
    51 	private JTable tabulka;
    52 
    53 	public Panel(Model model) {
    54 		this.model = model;
    55 		initComponents();
    56 
    57 		tlačítkoZamknout.setEnabled(model.isZámekPodporovaný());
    58 		tlačítkoZamknout.setToolTipText(model.isZámekPodporovaný()
    59 			? překlady.getString("zamknout.popis")
    60 			: překlady.getString("chyba.lzeZamknoutJenSoubor"));
    61 
    62 		tabulka = new JTable(model);
    63 		nastavEditor();
    64 		tabulka.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    65 		posuvnýPanel.setViewportView(tabulka);
    66 
    67 		tabulka.setRowHeight((int) (tabulka.getRowHeight() * 1.3));
    68 
    69 		// Výběr aktuálního atributu v tabulce:
    70 		tabulka.getSelectionModel().addListSelectionListener(
    71 			new ListSelectionListener() {
    72 
    73 			@Override
    74 			public void valueChanged(ListSelectionEvent e) {
    75 				int řádek = tabulka.getSelectedRow();
    76 				if (řádek < 0) vybranýAtribut = null;
    77 				else vybranýAtribut = getModel().getAtribut(řádek);
    78 				aktualizujPovolenéÚpravy();
    79 			}
    80 		});
    81 
    82 		// Buňky tabulky editovatelné po stisku mezerníku:
    83 		tabulka.getInputMap()
    84 			.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "startEditing");
    85 
    86 		aktualizujPovolenéÚpravy();
    87 
    88 		// TODO: Provádět IO operace v jiném vlákně
    89 		// SwingWorker.doInBackground() + SwingUtilities.invokeLater()
    90 	}
    91 
    92 	private void aktualizujPovolenéÚpravy() {
    93 		Konfigurace k = model.getKonfigurace();
    94 		switch (k.getRežimZamykání()) {
    95 			case VYPNUTÉ:
    96 				tlačítkoZamknout.setVisible(false);
    97 				setPovolenéÚpravy(true);
    98 				break;
    99 			case VOLITELNÉ:
   100 				setPovolenéÚpravy(true);
   101 				break;
   102 			case POVINNÉ:
   103 				setPovolenéÚpravy(tlačítkoZamknout.isSelected());
   104 				break;
   105 			default:
   106 				break;
   107 		}
   108 	}
   109 
   110 	private void setPovolenéÚpravy(boolean povolené) {
   111 		if (!povolené) {
   112 			TableCellEditor ce = tabulka.getCellEditor();
   113 			if (ce != null) ce.cancelCellEditing();
   114 			tabulka.clearSelection();
   115 		}
   116 
   117 		tabulka.setEnabled(povolené);
   118 		tlačítkoPřidat.setEnabled(povolené);
   119 		tlačítkoSmazat.setEnabled(povolené && tabulka.getSelectedRow() > -1);
   120 	}
   121 
   122 	private void nastavEditor() {
   123 		tabulka.getColumnModel().getColumn(SLOUPEC_NÁZVU)
   124 			.setCellEditor(new EditorNázvůAtributů(model.getKonfigurace()));
   125 		tabulka.getColumnModel().getColumn(SLOUPEC_HODNOTY)
   126 			.setCellEditor(new EditorHodnotAtributů(model.getKonfigurace()));
   127 	}
   128 
   129 	private Model getModel() {
   130 		return model;
   131 	}
   132 
   133 	public void setModel(Model model) {
   134 		this.model = model;
   135 		tabulka.setModel(model);
   136 		nastavEditor();
   137 	}
   138 
   139 	private void zobrazChybovouHlášku(String hláška, Throwable chyba) {
   140 		JOptionPane.showMessageDialog(this, hláška + "\n"
   141 			+ chyba.getLocalizedMessage(),
   142 			překlady.getString("chyba.titulek"), JOptionPane.ERROR_MESSAGE);
   143 		log.log(Level.WARNING, hláška, chyba);
   144 	}
   145 
   146 	private void kopírujDoSchránky() {
   147 		try {
   148 			StringWriter výstup = new StringWriter();
   149 			CSV csv = new CSV(výstup);
   150 
   151 			csv.hodnota(překlady.getString("tabulka.název").toLowerCase());
   152 			csv.hodnota(překlady.getString("tabulka.hodnota").toLowerCase());
   153 			csv.konecŘádku();
   154 
   155 			for (int i = 0; i < model.getRowCount(); i++) {
   156 				csv.hodnota(String.valueOf(model.getValueAt(i, 0)));
   157 				csv.hodnota(String.valueOf(model.getValueAt(i, 1)));
   158 				csv.konecŘádku();
   159 			}
   160 
   161 			Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
   162 				new StringSelection(výstup.toString()),
   163 				null
   164 			);
   165 		} catch (Exception e) {
   166 			zobrazChybovouHlášku(překlady
   167 				.getString("chyba.nepodařiloSeZkopírovat"), e);
   168 		}
   169 	}
   170 
   171 	@SuppressWarnings("unchecked")
   172     // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
   173     private void initComponents() {
   174 
   175         posuvnýPanel = new javax.swing.JScrollPane();
   176         tlačítkoPřidat = new javax.swing.JButton();
   177         tlačítkoSmazat = new javax.swing.JButton();
   178         tlačítkoZnovuNačíst = new javax.swing.JButton();
   179         tlačítkoZamknout = new javax.swing.JToggleButton();
   180         tlačítkoKopírovat = new javax.swing.JButton();
   181 
   182         tlačítkoPřidat.setMnemonic('p');
   183         java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("cz/frantovo/rozsireneatributy/Překlady"); // NOI18N
   184         tlačítkoPřidat.setText(bundle.getString("přidatAtribut")); // NOI18N
   185         tlačítkoPřidat.addActionListener(new java.awt.event.ActionListener() {
   186             public void actionPerformed(java.awt.event.ActionEvent evt) {
   187                 tlačítkoPřidatActionPerformed(evt);
   188             }
   189         });
   190 
   191         tlačítkoSmazat.setMnemonic('s');
   192         tlačítkoSmazat.setText(bundle.getString("smazatAtribut")); // NOI18N
   193         tlačítkoSmazat.setEnabled(false);
   194         tlačítkoSmazat.addActionListener(new java.awt.event.ActionListener() {
   195             public void actionPerformed(java.awt.event.ActionEvent evt) {
   196                 tlačítkoSmazatActionPerformed(evt);
   197             }
   198         });
   199 
   200         tlačítkoZnovuNačíst.setMnemonic('z');
   201         tlačítkoZnovuNačíst.setText(bundle.getString("znovuNačíst")); // NOI18N
   202         tlačítkoZnovuNačíst.addActionListener(new java.awt.event.ActionListener() {
   203             public void actionPerformed(java.awt.event.ActionEvent evt) {
   204                 tlačítkoZnovuNačístActionPerformed(evt);
   205             }
   206         });
   207 
   208         tlačítkoZamknout.setText(bundle.getString("zamknout")); // NOI18N
   209         tlačítkoZamknout.addActionListener(new java.awt.event.ActionListener() {
   210             public void actionPerformed(java.awt.event.ActionEvent evt) {
   211                 tlačítkoZamknoutActionPerformed(evt);
   212             }
   213         });
   214 
   215         tlačítkoKopírovat.setText(bundle.getString("schránka.kopírovat")); // NOI18N
   216         tlačítkoKopírovat.addActionListener(new java.awt.event.ActionListener() {
   217             public void actionPerformed(java.awt.event.ActionEvent evt) {
   218                 tlačítkoKopírovatActionPerformed(evt);
   219             }
   220         });
   221 
   222         javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
   223         this.setLayout(layout);
   224         layout.setHorizontalGroup(
   225             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
   226             .addGroup(layout.createSequentialGroup()
   227                 .addContainerGap()
   228                 .addComponent(tlačítkoPřidat)
   229                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
   230                 .addComponent(tlačítkoSmazat)
   231                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
   232                 .addComponent(tlačítkoZnovuNačíst)
   233                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
   234                 .addComponent(tlačítkoZamknout)
   235                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
   236                 .addComponent(tlačítkoKopírovat)
   237                 .addContainerGap(25, Short.MAX_VALUE))
   238             .addComponent(posuvnýPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 543, Short.MAX_VALUE)
   239         );
   240         layout.setVerticalGroup(
   241             layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
   242             .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
   243                 .addComponent(posuvnýPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 277, Short.MAX_VALUE)
   244                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
   245                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
   246                     .addComponent(tlačítkoPřidat)
   247                     .addComponent(tlačítkoSmazat)
   248                     .addComponent(tlačítkoZnovuNačíst)
   249                     .addComponent(tlačítkoZamknout)
   250                     .addComponent(tlačítkoKopírovat))
   251                 .addContainerGap())
   252         );
   253     }// </editor-fold>//GEN-END:initComponents
   254 
   255 	private void tlačítkoPřidatActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tlačítkoPřidatActionPerformed
   256 		model.přidejAtribut(new Atribut());
   257 	}//GEN-LAST:event_tlačítkoPřidatActionPerformed
   258 
   259 	private void tlačítkoSmazatActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tlačítkoSmazatActionPerformed
   260 		try {
   261 			model.odeberAtribut(vybranýAtribut);
   262 		} catch (IOException e) {
   263 			zobrazChybovouHlášku(překlady
   264 				.getString("chyba.nepodařiloSeSmazat"), e);
   265 		}
   266 	}//GEN-LAST:event_tlačítkoSmazatActionPerformed
   267 
   268 	private void tlačítkoZnovuNačístActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tlačítkoZnovuNačístActionPerformed
   269 		try {
   270 			model.načtiAtributy();
   271 		} catch (IOException e) {
   272 			zobrazChybovouHlášku(překlady
   273 				.getString("chyba.nepodařiloSeNačíst"), e);
   274 		}
   275 	}//GEN-LAST:event_tlačítkoZnovuNačístActionPerformed
   276 
   277     private void tlačítkoZamknoutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tlačítkoZamknoutActionPerformed
   278 		try {
   279 			aktualizujPovolenéÚpravy();
   280 			model.nastavZámek(tlačítkoZamknout.isSelected());
   281 		} catch (Exception e) {
   282 			zobrazChybovouHlášku(překlady
   283 				.getString("chyba.nepodařiloSeNastavitZámek"), e);
   284 		}
   285     }//GEN-LAST:event_tlačítkoZamknoutActionPerformed
   286 
   287     private void tlačítkoKopírovatActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tlačítkoKopírovatActionPerformed
   288 		kopírujDoSchránky();
   289     }//GEN-LAST:event_tlačítkoKopírovatActionPerformed
   290 
   291     // Variables declaration - do not modify//GEN-BEGIN:variables
   292     private javax.swing.JScrollPane posuvnýPanel;
   293     private javax.swing.JButton tlačítkoKopírovat;
   294     private javax.swing.JButton tlačítkoPřidat;
   295     private javax.swing.JButton tlačítkoSmazat;
   296     private javax.swing.JToggleButton tlačítkoZamknout;
   297     private javax.swing.JButton tlačítkoZnovuNačíst;
   298     // End of variables declaration//GEN-END:variables
   299 }