Last active
March 30, 2019 04:02
-
-
Save uvlad7/ad5831e2469c3e1a2146acd530c71870 to your computer and use it in GitHub Desktop.
УП 5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract class Cell { | |
private String renderedValue; | |
public Cell(String renderedValue) { | |
this.renderedValue = renderedValue; | |
} | |
public Cell() { | |
this.renderedValue = ""; | |
} | |
public void setRenderedValue(String renderedValue) { | |
this.renderedValue = renderedValue; | |
} | |
abstract public Type getType(); | |
abstract public Object getValue(); | |
public String getEditableValue() { | |
return renderedValue; | |
} | |
@Override | |
public String toString() { | |
return renderedValue; | |
} | |
public enum Type { | |
INT, | |
DATE, | |
FINT, | |
FDATE | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class CycleRefException extends ExcelException { | |
public CycleRefException(String message) { | |
super(message); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.text.SimpleDateFormat; | |
import java.util.Calendar; | |
public class DateCell extends Cell { | |
private Calendar value; | |
public DateCell(Calendar value) { | |
this.value = value; | |
SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy"); | |
setRenderedValue(format.format(value.getTime())); | |
} | |
public DateCell(Calendar value, String renderedValue) { | |
super(renderedValue); | |
this.value = value; | |
} | |
@Override | |
public Calendar getValue() { | |
return value; | |
} | |
@Override | |
public Type getType() { | |
return Type.DATE; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class DateException extends ExcelException { | |
public DateException(String message) { | |
super(message); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ExcelException extends Exception { | |
public ExcelException(String message) { | |
super(message); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.List; | |
public class FuncCell extends Cell { | |
private String editableValue; | |
private Type type; | |
private Long value; | |
private List<Long> constArgs; | |
private List<Link> links; | |
private FuncType funcType; | |
private boolean containsDate; | |
public FuncCell(String editableValue, List<Long> constArgs, List<Link> links, FuncType funcType, boolean containsDate) { | |
this.editableValue = editableValue; | |
this.constArgs = constArgs; | |
this.links = links; | |
this.funcType = funcType; | |
this.containsDate = containsDate; | |
} | |
@Override | |
public String getEditableValue() { | |
return editableValue; | |
} | |
public void setType(Type type) { | |
this.type = type; | |
} | |
public void setValue(Long value) { | |
this.value = value; | |
} | |
public List<Long> getConstArgs() { | |
return constArgs; | |
} | |
public FuncType getFuncType() { | |
return funcType; | |
} | |
public List<Link> getLinks() { | |
return links; | |
} | |
public boolean getContainsDate() { | |
return containsDate; | |
} | |
@Override | |
public Long getValue() { | |
return value; | |
} | |
@Override | |
public Type getType() { | |
return type; | |
} | |
public enum FuncType { | |
SUM, | |
MIN, | |
MAX | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class FuncFormatException extends ExcelException { | |
public FuncFormatException(String message) { | |
super(message); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class IntCell extends Cell { | |
private Long value; | |
public IntCell(Long value) { | |
super(((value == null) ? "" : value.toString())); | |
this.value = ((value == null) ? null : value * 86400000); | |
} | |
@Override | |
public Long getValue() { | |
return value; | |
} | |
@Override | |
public Type getType() { | |
return Type.INT; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Main { | |
public static void main(String[] args) { | |
new MyController(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.swing.*; | |
import javax.swing.border.LineBorder; | |
import javax.swing.table.TableCellEditor; | |
import java.awt.*; | |
public class MyCellEditor extends DefaultCellEditor implements TableCellEditor { | |
Cell value; | |
MyController controller; | |
MyTable view; | |
JTable table; | |
public MyCellEditor(JTextField textField, MyController controller, MyTable view, JTable table) { | |
super(textField); | |
this.controller = controller; | |
this.view = view; | |
this.table = table; | |
} | |
public boolean stopCellEditing() { | |
try { | |
value = controller.addCell(table.getEditingColumn(), table.getEditingRow(), (String) super.getCellEditorValue()); | |
} catch (DateException e) { | |
((JComponent) getComponent()).setBorder(new LineBorder(Color.red)); | |
SwingUtilities.invokeLater(() -> | |
JOptionPane.showMessageDialog(view, e.getMessage(), "Некорректная дата", JOptionPane.ERROR_MESSAGE) | |
); | |
return false; | |
} catch (FuncFormatException e) { | |
((JComponent) getComponent()).setBorder(new LineBorder(Color.red)); | |
SwingUtilities.invokeLater(() -> | |
JOptionPane.showMessageDialog(view, e.getMessage(), "Некорректная запись функции", JOptionPane.ERROR_MESSAGE) | |
); | |
return false; | |
} catch (CycleRefException e) { | |
((JComponent) getComponent()).setBorder(new LineBorder(Color.red)); | |
SwingUtilities.invokeLater(() -> | |
JOptionPane.showMessageDialog(view, e.getMessage(), "Циклическая ссылка", JOptionPane.ERROR_MESSAGE) | |
); | |
return false; | |
} catch (ExcelException e) { | |
((JComponent) getComponent()).setBorder(new LineBorder(Color.red)); | |
SwingUtilities.invokeLater(() -> | |
JOptionPane.showMessageDialog(view, e.getMessage(), "Некорректный формат", JOptionPane.ERROR_MESSAGE) | |
); | |
return false; | |
} | |
return super.stopCellEditing(); | |
} | |
public Component getTableCellEditorComponent(JTable table, Object value, | |
boolean isSelected, | |
int row, int column) { | |
this.value = null; | |
((JComponent) getComponent()).setBorder(new LineBorder(Color.black)); | |
Cell cell = (Cell) value; | |
return super.getTableCellEditorComponent(table, cell.getEditableValue(), isSelected, row, column); | |
} | |
public Cell getCellEditorValue() { | |
return value; | |
} | |
/*@Override | |
public void cancelCellEditing() { | |
value = new IntCell(null); | |
super.cancelCellEditing(); | |
}*/ | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.swing.*; | |
import javax.swing.event.TableModelEvent; | |
import javax.swing.event.TableModelListener; | |
import java.io.File; | |
import java.io.FileNotFoundException; | |
import java.io.PrintStream; | |
import java.text.ParseException; | |
import java.text.SimpleDateFormat; | |
import java.util.*; | |
public class MyController implements TableModelListener { | |
private MyModel model; | |
private MyTable view; | |
private List<List<Integer>> observers; | |
private List<List<Integer>> observed; | |
private int maxFilledCol; | |
private int maxFilledRow; | |
public MyController() { | |
model = new MyModel(this); | |
view = new MyTable(model, this); | |
model.addTableModelListener(this); | |
observed = new ArrayList<>(3328); | |
observers = new ArrayList<>(3328); | |
for (int i = 0; i < 3328; i++) { | |
observed.add(new ArrayList<>()); | |
observers.add(new ArrayList<>()); | |
} | |
} | |
public Cell addCell(int col, int row, String value) throws ExcelException { | |
Integer pos = row * 26 + col; | |
List<Integer> observedByCur = observed.get(row * 26 + col); | |
int size = observedByCur.size(); | |
for (int i = 0; i < size; i++) { | |
observers.get(observedByCur.get(i)).remove(pos); | |
} | |
observedByCur.clear(); | |
if (value.equals("")) { | |
return new IntCell(null); | |
} | |
if (value.charAt(0) == '=') { | |
List<String> tokens = MyParser.parseFunc(value.substring(1)); | |
List<Long> constArgs = new ArrayList<>(); | |
List<Link> links = new ArrayList<>(); | |
Integer link; | |
boolean containsDate = false; | |
FuncCell.FuncType funcType; | |
if (tokens.get(0).equals("MAX")) { | |
funcType = FuncCell.FuncType.MAX; | |
} else if (tokens.get(0).equals("MIN")) { | |
funcType = FuncCell.FuncType.MIN; | |
} else funcType = FuncCell.FuncType.SUM; | |
size = tokens.size(); | |
for (int i = 1; i < size; i++) { | |
if ((tokens.get(i).equals(";")) || (tokens.get(i).equals("+")) || (tokens.get(i).equals("-"))) { | |
continue; | |
} else if ((tokens.get(i).equals(":"))) { | |
int maxl = Integer.parseInt(tokens.get(i + 1).substring(1)); | |
int maxj = tokens.get(i + 1).charAt(0) - 65; | |
for (int l = Integer.parseInt(tokens.get(i - 1).substring(1)); l <= maxl; l++) { | |
for (int j = tokens.get(i - 1).charAt(0) - 65; j <= maxj; j++) { | |
link = j + 26 * l - 26; | |
links.add(new Link(1, link)); | |
observedByCur.add(link); | |
observers.get(link).add(pos); | |
if (link == row * 26 + col) | |
throw new CycleRefException("Функция содержит ссылку на текущую ячейку"); | |
if (isCycle(row * 26 + col, row * 26 + col, link)) | |
throw new CycleRefException("Функция содержит циклическую ссылку на текущую ячейку"); | |
} | |
} | |
} else if (MyParser.intVerify(tokens.get(i))) { | |
try { | |
if (tokens.get(i - 1).equals("-")) | |
constArgs.add(-86400000L * Integer.parseInt(tokens.get(i))); | |
else | |
constArgs.add(86400000L * Integer.parseInt(tokens.get(i))); | |
} catch (NumberFormatException e) { | |
throw new ExcelException("Слишком длинное число"); | |
} | |
} else if (MyParser.smellsLikeDate(tokens.get(i))) { | |
containsDate = true; | |
if (tokens.get(i - 1).equals("-")) | |
constArgs.add(-1 * parseDate(tokens.get(i)).getTime().getTime()); | |
else | |
constArgs.add(parseDate(tokens.get(i)).getTime().getTime()); | |
} else if ((tokens.get(i - 1).equals(":")) || ((i < size - 1) && (tokens.get(i + 1).equals(":")))) { | |
continue; | |
} else { | |
link = tokens.get(i).charAt(0) - 91 + Integer.parseInt(tokens.get(i).substring(1)) * 26; | |
if (tokens.get(i - 1).equals("-")) | |
links.add(new Link(-1, link)); | |
else | |
links.add(new Link(1, link)); | |
observedByCur.add(link); | |
observers.get(link).add(pos); | |
if (link == row * 26 + col) | |
throw new CycleRefException("Функция содержит ссылку на текущую ячейку"); | |
if (isCycle(row * 26 + col, row * 26 + col, link)) | |
throw new CycleRefException("Функция содержит циклическую ссылку на текущую ячейку"); | |
} | |
} | |
maxFilledCol = Math.max(maxFilledCol, col); | |
maxFilledRow = Math.max(maxFilledRow, row); | |
return new FuncCell(value, constArgs, links, funcType, containsDate); | |
} else if (MyParser.intVerify(value)) { | |
try { | |
maxFilledCol = Math.max(maxFilledCol, col); | |
maxFilledRow = Math.max(maxFilledRow, row); | |
return new IntCell((long) Integer.parseInt(value)); | |
} catch (NumberFormatException e) { | |
throw new ExcelException("Слишком длинное число"); | |
} | |
} | |
if (MyParser.smellsLikeDate(value)) { | |
if (MyParser.dateVerify(value)) { | |
maxFilledCol = Math.max(maxFilledCol, col); | |
maxFilledRow = Math.max(maxFilledRow, row); | |
return new DateCell(parseDate(value), value); | |
} else throw new DateException("Дата не существует"); | |
} | |
throw new ExcelException("Формат не распознан"); | |
} | |
private Calendar parseDate(String value) { | |
SimpleDateFormat format1 = new SimpleDateFormat("dd.MM.yyyy"); | |
SimpleDateFormat format3 = new SimpleDateFormat("M/d/yyyy"); | |
Calendar calendar = Calendar.getInstance(); | |
try { | |
calendar.setTime(format1.parse(value)); | |
} catch (ParseException e) { | |
} | |
try { | |
calendar.setTime(format3.parse(value)); | |
} catch (ParseException e) { | |
} | |
return calendar; | |
} | |
private boolean isCycle(int checked, int cur, int link) { | |
if (link == checked) | |
return true; | |
boolean cycle = false; | |
for (int i = 0; i < observed.get(cur).size(); i++) { | |
if (isCycle(checked, link, observed.get(cur).get(i))) { | |
cycle = true; | |
break; | |
} | |
} | |
return cycle; | |
} | |
private void updateCell(int col, int row) { | |
int size; | |
if (model.getValueAt(row, col) instanceof FuncCell) { | |
FuncCell cell = (FuncCell) model.getValueAt(row, col); | |
Cell linkedCell; | |
List<Long> constArgs = cell.getConstArgs(); | |
List<Link> links = cell.getLinks(); | |
Long value = 0L; | |
boolean isDate = cell.getContainsDate(); | |
if (FuncCell.FuncType.MAX.equals(cell.getFuncType())) { | |
size = constArgs.size(); | |
if (size != 0) | |
value = constArgs.get(0); | |
for (int i = 1; i < size; i++) { | |
value = Math.max(value, constArgs.get(i)); | |
} | |
size = links.size(); | |
if (size != 0) { | |
linkedCell = (Cell) model.getValueAt(links.get(0).link / 26, links.get(0).link % 26); | |
if (Cell.Type.DATE.equals(linkedCell.getType())) { | |
isDate = true; | |
value = Math.max(value, ((Calendar) linkedCell.getValue()).getTime().getTime()); | |
} else { | |
if (linkedCell.getValue() != null) | |
value = Math.max(value, (Long) linkedCell.getValue()); | |
if (Cell.Type.FDATE.equals(linkedCell.getType())) | |
isDate = true; | |
} | |
} | |
for (int i = 1; i < size; i++) { | |
linkedCell = (Cell) model.getValueAt(links.get(i).link / 26, links.get(i).link % 26); | |
if (Cell.Type.DATE.equals(linkedCell.getType())) { | |
isDate = true; | |
value = Math.max(value, ((Calendar) linkedCell.getValue()).getTime().getTime()); | |
} else { | |
if (linkedCell.getValue() != null) | |
value = Math.max(value, (Long) linkedCell.getValue()); | |
if (Cell.Type.FDATE.equals(linkedCell.getType())) | |
isDate = true; | |
} | |
} | |
} else if (FuncCell.FuncType.MIN.equals(cell.getFuncType())) { | |
size = constArgs.size(); | |
if (size != 0) | |
value = constArgs.get(0); | |
for (int i = 1; i < size; i++) { | |
value = Math.min(value, constArgs.get(i)); | |
} | |
size = links.size(); | |
if (size != 0) { | |
linkedCell = (Cell) model.getValueAt(links.get(0).link / 26, links.get(0).link % 26); | |
if (Cell.Type.DATE.equals(linkedCell.getType())) { | |
isDate = true; | |
value = Math.min(value, ((Calendar) linkedCell.getValue()).getTime().getTime()); | |
} else { | |
if (linkedCell.getValue() != null) | |
value = Math.min(value, (Long) linkedCell.getValue()); | |
if (Cell.Type.FDATE.equals(linkedCell.getType())) | |
isDate = true; | |
} | |
} | |
for (int i = 1; i < size; i++) { | |
linkedCell = (Cell) model.getValueAt(links.get(i).link / 26, links.get(i).link % 26); | |
if (Cell.Type.DATE.equals(linkedCell.getType())) { | |
isDate = true; | |
value = Math.min(value, ((Calendar) linkedCell.getValue()).getTime().getTime()); | |
} else { | |
if (linkedCell.getValue() != null) | |
value = Math.min(value, (Long) linkedCell.getValue()); | |
if (Cell.Type.FDATE.equals(linkedCell.getType())) | |
isDate = true; | |
} | |
} | |
} else { | |
size = constArgs.size(); | |
for (int i = 0; i < size; i++) { | |
value += constArgs.get(i); | |
} | |
size = links.size(); | |
for (int i = 0; i < size; i++) { | |
linkedCell = (Cell) model.getValueAt(links.get(i).link / 26, links.get(i).link % 26); | |
if (Cell.Type.DATE.equals(linkedCell.getType())) { | |
isDate = true; | |
value += links.get(i).abs * ((Calendar) linkedCell.getValue()).getTime().getTime(); | |
} else { | |
if (linkedCell.getValue() != null) | |
value += links.get(i).abs * (Long) linkedCell.getValue(); | |
if (Cell.Type.FDATE.equals(linkedCell.getType())) | |
isDate = true; | |
} | |
} | |
} | |
cell.setValue(value); | |
if (!isDate) { | |
value /= 86400000; | |
cell.setRenderedValue((value).toString()); | |
cell.setType(Cell.Type.FINT); | |
} else { | |
SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy"); | |
cell.setRenderedValue(format.format(new Date(value))); | |
cell.setType(Cell.Type.FDATE); | |
} | |
} | |
List<Integer> observersOfCur = observers.get(row * 26 + col); | |
size = observersOfCur.size(); | |
for (int i = 0; i < size; i++) { | |
updateCell(observersOfCur.get(i) % 26, observersOfCur.get(i) / 26); | |
} | |
} | |
@Override | |
public void tableChanged(TableModelEvent e) { | |
if ((e.getColumn() != -1) && (e.getLastRow() != -1)) | |
updateCell(e.getColumn(), e.getLastRow()); | |
view.updateUI(); | |
} | |
public void save(String path) { | |
try (PrintStream printStream = new PrintStream(path)) { | |
StringBuilder stringBuilder = new StringBuilder(); | |
Cell cell; | |
for (int i = 0; i <= maxFilledRow; i++) { | |
for (int j = 0; j <= maxFilledCol; j++) { | |
cell = (Cell) model.getValueAt(i, j); | |
stringBuilder.append(cell.getEditableValue()).append(','); | |
} | |
while (stringBuilder.charAt(stringBuilder.length() - 1) == ',') | |
stringBuilder.deleteCharAt(stringBuilder.length() - 1); | |
stringBuilder.append("\r\n"); | |
} | |
printStream.print(stringBuilder); | |
} catch (FileNotFoundException ex) { | |
JOptionPane.showMessageDialog(view, "Ошибка: путь не существует", "Сохранить", | |
JOptionPane.ERROR_MESSAGE, new ImageIcon("src\\save.png")); | |
} | |
} | |
public void open(String path) { | |
try (Scanner scanner = new Scanner(new File(path))) { | |
model.clear(); | |
for (int i = 0; i < 3328; i++) { | |
observed.get(i).clear(); | |
observers.get(i).clear(); | |
} | |
maxFilledCol = 0; | |
maxFilledRow = 0; | |
imp(scanner); | |
} catch (FileNotFoundException ex) { | |
JOptionPane.showMessageDialog(view, "Ошибка: файл не найден", "Открыть", | |
JOptionPane.ERROR_MESSAGE, new ImageIcon("src\\open.png")); | |
} | |
} | |
public void insert(String path) { | |
try (Scanner scanner = new Scanner(new File(path))) { | |
imp(scanner); | |
} catch (FileNotFoundException ex) { | |
JOptionPane.showMessageDialog(view, "Ошибка: файл не найден", "Импортировать", | |
JOptionPane.ERROR_MESSAGE, new ImageIcon("src\\import.png")); | |
} | |
} | |
private void imp(Scanner scanner) { | |
StringTokenizer tokenizer; | |
int i, j; | |
String token; | |
i = 0; | |
while (scanner.hasNextLine()) { | |
tokenizer = new StringTokenizer(scanner.nextLine(), "[,]", true); | |
j = 0; | |
while (tokenizer.hasMoreTokens()) { | |
token = tokenizer.nextToken(); | |
if (!token.equals(",")) { | |
try { | |
model.setValueAt(addCell(j, i, token), i, j); | |
} catch (DateException e) { | |
String label = (char) (65 + j) + Integer.toString(i); | |
SwingUtilities.invokeLater(() -> | |
JOptionPane.showMessageDialog(view, e.getMessage(), "Некорректная дата: " + label, JOptionPane.ERROR_MESSAGE) | |
); | |
} catch (FuncFormatException e) { | |
String label = (char) (65 + j) + Integer.toString(i); | |
SwingUtilities.invokeLater(() -> | |
JOptionPane.showMessageDialog(view, e.getMessage(), "Некорректная запись функции: " + label, JOptionPane.ERROR_MESSAGE) | |
); | |
} catch (CycleRefException e) { | |
String label = (char) (65 + j) + Integer.toString(i); | |
SwingUtilities.invokeLater(() -> | |
JOptionPane.showMessageDialog(view, e.getMessage(), "Циклическая ссылка: " + label, JOptionPane.ERROR_MESSAGE) | |
); | |
} catch (ExcelException e) { | |
String label = (char) (65 + j) + Integer.toString(i); | |
SwingUtilities.invokeLater(() -> | |
JOptionPane.showMessageDialog(view, e.getMessage(), "Некорректный формат: " + label, JOptionPane.ERROR_MESSAGE) | |
); | |
} | |
} else j++; | |
} | |
i++; | |
} | |
} | |
} | |
class Link { | |
int abs; | |
int link; | |
public Link(int abs, int link) { | |
this.abs = abs; | |
this.link = link; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.swing.table.DefaultTableModel; | |
public class MyModel extends DefaultTableModel { | |
private MyController controller; | |
public MyModel(MyController controller) { | |
this.controller = controller; | |
clear(); | |
} | |
@Override | |
public Class getColumnClass(int column) { | |
return String.class; | |
} | |
public void clear() { | |
Cell[][] data = new IntCell[128][26]; | |
Cell[] row = new IntCell[26]; | |
String[] names = new String[26]; | |
for (int i = 0; i < 26; i++) { | |
names[i] = Character.toString(((char) (65 + i))); | |
row[i] = new IntCell(null); | |
} | |
for (int j = 0; j < 128; j++) { | |
data[j] = row; | |
} | |
setDataVector(data, names); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.regex.Matcher; | |
import java.util.regex.Pattern; | |
public class MyParser { | |
private static Pattern intPattern = Pattern.compile("^(?:(?:-?[1-9]\\d*)|0)$"); | |
private static Pattern likeDatePattern = Pattern.compile("^(?:(?:\\d{2}\\.\\d{2}\\.\\d{4})|(?:\\d{1,2}/\\d{1,2}/\\d{4}))$"); | |
private static Pattern datePattern = Pattern.compile("^(?:(?:(?:(?:(?:(?:0[1-9])|(?:1\\d)|(?:2[0-8]))\\.(?:(?:0[1-9])|(?:1[0-2])))|(?:(?:(?:29)|(?:30))\\.(?:(?:0[13-9])|(?:1[0-2])))|(?:31\\.(?:(?:0[13578])|(?:1[02]))))" + | |
"\\.(?:(?!0000)\\d{4}))" + | |
"|(?:(?:(?:(?:(?:[1-9])|(?:1[0-2]))/(?:(?:[1-9])|(?:1\\d)|(?:2[0-8])))|(?:(?:(?:[13-9])|(?:1[0-2]))/(?:(?:29)|(?:30)))|(?:(?:(?:[13578])|(?:1[02]))/31))" + | |
"/(?:(?!0000)\\d{4}))" + | |
"|(?:(?:(?:29\\.02\\.)|(?:2/29/))(?:(?:(?:(?:[13579][26])|(?:[2468][048])|(?:0[48]))00)|" + | |
"(?:\\d{2}(?:(?:[13579][26])|(?:[2468][048])|(?:0[48]))))))$"); | |
private static Pattern likeLinkPattern = Pattern.compile("^(?:[A-Z]\\d{1,3})$"); | |
private static Pattern linkPattern = Pattern.compile("^(?:[A-Z](?:(?:[1-9])|(?:[1-9]\\d)|(?:1[01]\\d)|(?:12[0-8])))$"); | |
private static Pattern sumPattern = Pattern.compile("^(?:(?:[A-Z]\\d{1,3})|(?:(?:\\d{2}\\.\\d{2}\\.\\d{4})|(?:\\d{1,2}/\\d{1,2}/\\d{4}))|(?:(?:-?[1-9]\\d*)|0))(?:[-+](?:(?:[A-Z]\\d{1,3})|(?:(?:\\d{2}\\.\\d{2}\\.\\d{4})|(?:\\d{1,2}/\\d{1,2}/\\d{4}))|(?:(?:-?[1-9]\\d*)|0)))*$"); | |
private static Pattern parseSumPattern = Pattern.compile("(?:[^-+]+)|(?:[-+])"); | |
private static Pattern minMaxPattern = Pattern.compile("^(?:MIN|MAX)\\((?:(?:(?:[A-Z]\\d{1,3}):(?:[A-Z]\\d{1,3}))|(?:(?:(?:[A-Z]\\d{1,3})|(?:(?:\\d{2}\\.\\d{2}\\.\\d{4})|(?:\\d{1,2}/\\d{1,2}/\\d{4}))|(?:(?:-?[1-9]\\d*)|0));(?:(?:[A-Z]\\d{1,3})|(?:(?:\\d{2}\\.\\d{2}\\.\\d{4})|(?:\\d{1,2}/\\d{1,2}/\\d{4}))|(?:(?:-?[1-9]\\d*)|0))))" + | |
"(?:;(?:(?:(?:[A-Z]\\d{1,3}):(?:[A-Z]\\d{1,3}))|(?:(?:[A-Z]\\d{1,3})|(?:(?:\\d{2}\\.\\d{2}\\.\\d{4})|(?:\\d{1,2}/\\d{1,2}/\\d{4}))|(?:(?:-?[1-9]\\d*)|0))))*\\)$"); | |
private static Pattern parseMinMaxPattern = Pattern.compile("(?:[^;:]+)|(?:[;:])"); | |
public static boolean intVerify(String text) { | |
return intPattern.matcher(text).matches(); | |
} | |
public static boolean smellsLikeDate(String text) { | |
return likeDatePattern.matcher(text).matches(); | |
} | |
public static boolean smellsLikeLink(String text) { | |
return likeLinkPattern.matcher(text).matches(); | |
} | |
public static boolean dateVerify(String text) { | |
return datePattern.matcher(text).matches(); | |
} | |
public static boolean linkVerify(String text) { | |
return linkPattern.matcher(text).matches(); | |
} | |
private static boolean sumVerify(String text) { | |
return sumPattern.matcher(text).matches(); | |
} | |
private static boolean minMaxVerify(String text) { | |
return minMaxPattern.matcher(text).matches(); | |
} | |
private static List<String> parseSum(String text) { | |
List<String> list = new ArrayList<>(); | |
list.add("SUM"); | |
Matcher matcher = parseSumPattern.matcher(text); | |
while (matcher.find()) { | |
list.add(matcher.group()); | |
} | |
return list; | |
} | |
private static List<String> parseMinMax(String text) { | |
List<String> list = new ArrayList<>(); | |
if (text.charAt(2) == 'X') | |
list.add("MAX"); | |
else list.add("MIN"); | |
Matcher matcher = parseMinMaxPattern.matcher(text.substring(4, text.length() - 1)); | |
while (matcher.find()) { | |
list.add(matcher.group()); | |
} | |
return list; | |
} | |
public static List<String> parseFunc(String text) throws FuncFormatException { | |
List<String> tokens; | |
if (sumVerify(text)) { | |
tokens = parseSum(text); | |
} else if (minMaxVerify(text)) { | |
tokens = parseMinMax(text); | |
} else | |
throw new FuncFormatException("Запись не является формулой"); | |
int size = tokens.size(); | |
for (int i = 0; i < size; i++) { | |
if ((smellsLikeLink(tokens.get(i))) && (!linkVerify(tokens.get(i)))) | |
throw new FuncFormatException("Ячейка " + tokens.get(i) + " не существует"); | |
else if ((smellsLikeDate(tokens.get(i))) && (!dateVerify(tokens.get(i)))) | |
throw new FuncFormatException("Дата " + tokens.get(i) + " не существует"); | |
} | |
return tokens; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.swing.*; | |
import javax.swing.table.DefaultTableCellRenderer; | |
import java.awt.*; | |
public class MyRenderer extends DefaultTableCellRenderer { | |
private Font font; | |
private JLabel label; | |
public MyRenderer() { | |
font = new Font("Verdana", Font.PLAIN, 16); | |
} | |
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { | |
label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); | |
label.setHorizontalAlignment(SwingConstants.LEFT); | |
label.setFont(font); | |
if (value != null) | |
label.setText(value.toString()); | |
//label.setText(parser.parse(value.toString(), table)); | |
return label; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.swing.*; | |
import javax.swing.filechooser.FileNameExtensionFilter; | |
import javax.swing.table.DefaultTableCellRenderer; | |
import javax.swing.table.JTableHeader; | |
import java.awt.*; | |
import java.awt.event.ActionEvent; | |
import java.awt.event.ActionListener; | |
import java.awt.event.KeyEvent; | |
public class MyTable extends JFrame implements ActionListener { | |
private MyModel model; | |
private MyController controller; | |
private JTable table; | |
private JMenuBar menuBar; | |
private JMenu file; | |
private JMenuItem open; | |
private JMenuItem imp; | |
private JMenuItem save; | |
private JMenuItem saveAs; | |
private String filename; | |
public MyTable(MyModel model, MyController controller) { | |
super("Excel Date Lite"); | |
this.model = model; | |
this.controller = controller; | |
try { | |
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); | |
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) { | |
} | |
setIconImage(new ImageIcon("src\\excel.png").getImage()); | |
setSize(900, 600); | |
ListModel<String> listModel = new AbstractListModel<>() { | |
String[] headers; | |
{ | |
headers = new String[128]; | |
for (int i = 0; i < 128; i++) { | |
headers[i] = Integer.toString(i + 1); | |
} | |
} | |
public int getSize() { | |
return headers.length; | |
} | |
public String getElementAt(int index) { | |
return headers[index]; | |
} | |
}; | |
table = new JTable(model); | |
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); | |
table.getTableHeader().setReorderingAllowed(false); | |
table.getTableHeader().setDefaultRenderer(new HeaderRenderer(table)); | |
table.setDefaultRenderer(String.class, new MyRenderer()); | |
JTextField textField = new JTextField(); | |
textField.setFont(new Font("Verdana", Font.PLAIN, 16)); | |
textField.setHorizontalAlignment(SwingConstants.LEFT); | |
MyCellEditor cellEditor = new MyCellEditor(textField, controller, this, table); | |
table.setDefaultEditor(String.class, cellEditor); | |
table.setRowHeight(26); | |
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); | |
table.setColumnSelectionAllowed(true); | |
table.setRowSelectionAllowed(true); | |
JList<String> rowHeader = new JList<>(listModel); | |
rowHeader.setFixedCellWidth(50); | |
rowHeader.setFixedCellHeight(table.getRowHeight()); | |
rowHeader.setCellRenderer(new RowHeaderRenderer(table)); | |
JScrollPane scroll = new JScrollPane(table); | |
scroll.setRowHeaderView(rowHeader); | |
getContentPane().add(scroll, BorderLayout.CENTER); | |
menuBar = new JMenuBar(); | |
file = new JMenu("Файл"); | |
open = new JMenuItem("Открыть", new ImageIcon("src\\open.png")); | |
file.add(open); | |
imp = new JMenuItem("Импортировать", new ImageIcon("src\\import.png")); | |
file.add(imp); | |
save = new JMenuItem("Сохранить", new ImageIcon("src\\save.png")); | |
file.add(save); | |
saveAs = new JMenuItem("Сохранить как", new ImageIcon("src\\saveAs.png")); | |
file.add(saveAs); | |
open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK)); | |
imp.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, KeyEvent.CTRL_DOWN_MASK)); | |
save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK)); | |
saveAs.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK + KeyEvent.SHIFT_DOWN_MASK)); | |
menuBar.add(file); | |
setJMenuBar(menuBar); | |
open.addActionListener(this); | |
imp.addActionListener(this); | |
save.addActionListener(this); | |
saveAs.addActionListener(this); | |
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
pack(); | |
setSize(900, 600); | |
setLocationRelativeTo(null); | |
setVisible(true); | |
} | |
public void updateUI() { | |
SwingUtilities.invokeLater(() -> | |
table.updateUI() | |
); | |
} | |
@Override | |
public void actionPerformed(ActionEvent e) { | |
if (e.getSource() == open) { | |
if (open()) | |
controller.open(filename); | |
} else if (e.getSource() == imp) { | |
if (open()) | |
controller.insert(filename); | |
} else if (e.getSource() == save) { | |
if (filename != null) { | |
controller.save(filename); | |
} else { | |
saveAs(); | |
} | |
} else if (e.getSource() == saveAs) { | |
saveAs(); | |
} | |
} | |
private void saveAs() { | |
JFileChooser fileChooser = new JFileChooser("."); | |
fileChooser.setAcceptAllFileFilterUsed(false); | |
fileChooser.addChoosableFileFilter(new FileNameExtensionFilter("csv table file", "csv")); | |
if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { | |
filename = fileChooser.getDescription(fileChooser.getSelectedFile()); | |
controller.save(filename); | |
} | |
} | |
private boolean open() { | |
JFileChooser fileChooser = new JFileChooser("."); | |
fileChooser.setAcceptAllFileFilterUsed(false); | |
fileChooser.addChoosableFileFilter(new FileNameExtensionFilter("csv table file", "csv")); | |
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { | |
filename = fileChooser.getDescription(fileChooser.getSelectedFile()); | |
return true; | |
} | |
return false; | |
} | |
} | |
class RowHeaderRenderer extends DefaultListCellRenderer { | |
private JLabel label; | |
private JTableHeader header; | |
RowHeaderRenderer(JTable table) { | |
header = table.getTableHeader(); | |
} | |
@Override | |
public Component getListCellRendererComponent(JList list, | |
Object value, int index, boolean isSelected, boolean cellHasFocus) { | |
label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); | |
label.setText((value == null) ? "" : value.toString()); | |
label.setOpaque(true); | |
label.setBorder(UIManager.getBorder("TableHeader.cellBorder")); | |
label.setHorizontalAlignment(CENTER); | |
label.setForeground(header.getForeground()); | |
label.setBackground(header.getBackground()); | |
label.setFont(header.getFont()); | |
return label; | |
} | |
} | |
class HeaderRenderer extends DefaultTableCellRenderer { | |
private JLabel label; | |
private JTableHeader header; | |
HeaderRenderer(JTable table) { | |
header = table.getTableHeader(); | |
} | |
@Override | |
public Component getTableCellRendererComponent(JTable table, Object value, | |
boolean isSelected, boolean hasFocus, int row, int column) { | |
label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); | |
label.setText((value == null) ? "" : value.toString()); | |
label.setOpaque(true); | |
label.setBorder(UIManager.getBorder("TableHeader.cellBorder")); | |
label.setHorizontalAlignment(CENTER); | |
label.setForeground(header.getForeground()); | |
label.setBackground(header.getBackground()); | |
label.setFont(header.getFont()); | |
return label; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment