From 9afe737fef605bdfcf15a706215458ccd4f22fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Fr=C4=85cz?= Date: Tue, 17 Mar 2020 23:14:33 +0100 Subject: [PATCH] Line and SourceFile --- .../pl/fracz/mcr/comment/AbstractComment.java | 52 +++++++ .../mcr/comment/CommendNotAddedException.java | 4 + .../java/pl/fracz/mcr/comment/Comment.java | 41 ++++++ src/main/java/pl/fracz/mcr/source/Line.java | 117 +++++++++++++++ .../mcr/source/NoSelectedLineException.java | 6 + .../java/pl/fracz/mcr/source/SourceFile.java | 135 ++++++++++++++++++ 6 files changed, 355 insertions(+) create mode 100644 src/main/java/pl/fracz/mcr/comment/AbstractComment.java create mode 100644 src/main/java/pl/fracz/mcr/comment/CommendNotAddedException.java create mode 100644 src/main/java/pl/fracz/mcr/comment/Comment.java create mode 100644 src/main/java/pl/fracz/mcr/source/Line.java create mode 100644 src/main/java/pl/fracz/mcr/source/NoSelectedLineException.java create mode 100644 src/main/java/pl/fracz/mcr/source/SourceFile.java diff --git a/src/main/java/pl/fracz/mcr/comment/AbstractComment.java b/src/main/java/pl/fracz/mcr/comment/AbstractComment.java new file mode 100644 index 0000000..6908daa --- /dev/null +++ b/src/main/java/pl/fracz/mcr/comment/AbstractComment.java @@ -0,0 +1,52 @@ +package pl.fracz.mcr.comment; + +import pl.fracz.mcr.preferences.ApplicationSettings; +import pl.fracz.mcr.source.SourceFile; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class AbstractComment { + private final SimpleDateFormat CREATION_TIME_FORMAT = new SimpleDateFormat("HH:mm dd.MM.yyyy"); + + private final Type type; + + private final String author; + + protected SourceFile sourceFile; + + private Date date; + + private int lineNumber; + + public AbstractComment(Type type, int lineNumber) { + this.type = type; + this.author = ApplicationSettings.getAuthor(); + this.lineNumber = lineNumber; + this.date = new Date(System.currentTimeMillis()); + } + + public Type getType() { + return type; + } + + public Date getDate() { + return date; + } + + public String getDateFormatted() { + return CREATION_TIME_FORMAT.format(date); + } + + public int getLineNumber() { + return lineNumber; + } + + protected String getAuthor() { + return author; + } + + public static enum Type { + TEXT, VOICE + } +} diff --git a/src/main/java/pl/fracz/mcr/comment/CommendNotAddedException.java b/src/main/java/pl/fracz/mcr/comment/CommendNotAddedException.java new file mode 100644 index 0000000..82a95ff --- /dev/null +++ b/src/main/java/pl/fracz/mcr/comment/CommendNotAddedException.java @@ -0,0 +1,4 @@ +package pl.fracz.mcr.comment; + +public class CommentNotAddedException extends Exception { +} diff --git a/src/main/java/pl/fracz/mcr/comment/Comment.java b/src/main/java/pl/fracz/mcr/comment/Comment.java new file mode 100644 index 0000000..3961616 --- /dev/null +++ b/src/main/java/pl/fracz/mcr/comment/Comment.java @@ -0,0 +1,41 @@ +package pl.fracz.mcr.comment; + +import pl.fracz.mcr.source.Line; + +import java.io.File; + +public class Comment extends AbstractComment { + private String text; + + private File file; + + public Comment(AbstractComment.Type type, Line line) { + super(type, line.get()); + } + + public void setText(String text) { + checkValidType(AbstractComment.Type.TEXT); + this.text = text; + } + + public String getText() { + checkValidType(AbstractComment.Type.TEXT); + return text; + } + + public void setFile(File file) { + checkValidType(AbstractComment.Type.VOICE); + this.file = file; + } + + public File getFile() { + checkValidType(AbstractComment.Type.VOICE); + return file; + } + + private void checkValidType(AbstractComment.Type type) { + if (type != this.getType()) { + throw new IllegalArgumentException("The " + type + " comment is required to set this attribute"); + } + } +} diff --git a/src/main/java/pl/fracz/mcr/source/Line.java b/src/main/java/pl/fracz/mcr/source/Line.java new file mode 100644 index 0000000..ac3a611 --- /dev/null +++ b/src/main/java/pl/fracz/mcr/source/Line.java @@ -0,0 +1,117 @@ +package pl.fracz.mcr.source; + +/* + 2013-10-23, fracz, first implementation + 2013-10-30, fracz, added syntax highlighting + 2014-02-26, fracz, added ability to add voice comment + */ + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Color; +import android.graphics.Typeface; +import android.text.Html; +import android.widget.LinearLayout; +import android.widget.TextView; +import pl.fracz.mcr.comment.AbstractComment; +import pl.fracz.mcr.comment.Comment; +import pl.fracz.mcr.comment.CommentNotAddedException; + +import java.io.File; +import java.io.Serializable; +import java.util.List; + +/** + * View that represents one line of code. + */ +@SuppressLint("ViewConstructor") +public class Line extends LinearLayout implements Serializable { + private static final long serialVersionUID = 3076583280108678995L; + private static final int TWO = 2; + + private final int _lineNumber; + + private final String _lineOfCode; + + // holds the line number + private TextView lineNumberView; + + private TextView lineContent; + + private SourceFile sourceFile; + + private List comments; + + public Line(Context context, SourceFile sourceFile, int lineNumber, + String lineOfCode, boolean syntaxColor) { + super(context); + this.sourceFile = sourceFile; + this._lineNumber = lineNumber; + this._lineOfCode = lineOfCode; + setOrientation(LinearLayout.HORIZONTAL); + + lineNumberView = new TextView(getContext()); + lineNumberView.setText(String.format("%d.", lineNumber);); + lineNumberView.setSingleLine(); + lineNumberView.setWidth(30); + addView(lineNumberView); + + TextView lineContent = new TextView(getContext()); + addLineContent(syntaxColor); + } + + public int get() { + return _lineNumber; + } + + /** + * Adds a text comment. + * + * @param comment + * @throws CommentNotAddedException + */ + public void addTextComment(String comment) throws CommentNotAddedException { + Comment textComment = new Comment(AbstractComment.Type.TEXT, this); + textComment.setText(comment); + comments.add(textComment); + if (comments.size() > 0) { + lineNumberView.setBackgroundColor(Color.parseColor("#008000")); + } + } + + /** + * Adds a voice comment. + * + * @param recordedFile + * @throws CommentNotAddedException + */ + public void createVoiceComment(File recodedFile) throws CommentNotAddedException { + Comment voiceComment = new Comment(AbstractComment.Type.VOICE, this); + voiceComment.setFile(recodedFile); + comments.add(voiceComment); + if (comments.size() > 0) { + lineNumberView.setBackgroundColor(Color.parseColor("#008000")); + } + } + +// public void addVideoComment(File videoFile) throws CommentNotAddedException { +// } + + private void addLineContent(boolean syntaxColor){ + if (!syntaxColor || !SyntaxHighlighter.canBeHighlighted(syntaxColor)) + lineContent.setText(Html.fromHtml(lineOfCode)); + else + lineContent.setText(SyntaxHighlighter.highlight(Html.fromHtml(lineOfCode))); + lineContent.setTypeface(Typeface.MONOSPACE); + addView(lineContent); + } + + public List getComments(){ + return this.comments; + } + + public boolean hasConversation() { + sourceFile.markConversation(this); + return getComments().size() > TWO; + } +} diff --git a/src/main/java/pl/fracz/mcr/source/NoSelectedLineException.java b/src/main/java/pl/fracz/mcr/source/NoSelectedLineException.java new file mode 100644 index 0000000..1539638 --- /dev/null +++ b/src/main/java/pl/fracz/mcr/source/NoSelectedLineException.java @@ -0,0 +1,6 @@ +package pl.fracz.mcr.source; + +import pl.fracz.mcr.comment.CommentNotAddedException; + +public class NoSelectedLineException extends CommentNotAddedException { +} diff --git a/src/main/java/pl/fracz/mcr/source/SourceFile.java b/src/main/java/pl/fracz/mcr/source/SourceFile.java new file mode 100644 index 0000000..ea85e4e --- /dev/null +++ b/src/main/java/pl/fracz/mcr/source/SourceFile.java @@ -0,0 +1,135 @@ +package pl.fracz.mcr.source; + +import android.content.Context; +import android.graphics.Color; +import android.view.View; +import pl.fracz.mcr.comment.CommentNotAddedException; +import pl.fracz.mcr.preferences.ApplicationSettings; +import pl.fracz.mcr.syntax.PrettifyHighlighter; +import pl.fracz.mcr.syntax.SyntaxHighlighter; +import pl.fracz.mcr.util.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.StringTokenizer; + +public class SourceFile { + private static final SyntaxHighlighter SYNTAX_HIGHLIGHTER = new PrettifyHighlighter(); + + private static final Color SELECTED_LINE_COLOR = Color.parseColor("#444444"); + + private final View.OnClickListener lineHighlighter = view -> { + if (selectedLine != null) { + selectedLine.setBackgroundColor(Color.TRANSPARENT); + } + selectedLine = (Line) view; + selectedLine.setBackgroundColor(SELECTED_LINE_COLOR); + }; + + private final String sourceCode; + + private final String identifier; + + private final String language; + + private Line selectedLine; + + private String highlightedSourceCode; + + public SourceFile(String sourceCode, String language) { + this.sourceCode = sourceCode; + this.language = language; + this.identifier = calculateSHA1SourceChecksum(); + } + + private String calculateSHA1SourceChecksum() { + try { + MessageDigest md = MessageDigest.getInstance("SHA1"); + byte[] digest = md.digest(sourceCode.getBytes()); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < digest.length; i++) { + sb.append(Integer.toString((digest[i] & 0xff) + 0x100, 16).substring(1)); + } + return sb.toString(); + } catch (NoSuchAlgorithmException e) { + throw new AssertionError(); + } + } + + public Collection getLines(Context context) { + StringTokenizer tokenizer = new StringTokenizer(getHighlightedSourceCode(), "\n"); + Collection lines = new ArrayList(tokenizer.countTokens()); + while (tokenizer.hasMoreTokens()) { + Line line = new Line(context, this, lines.size() + 1, tokenizer.nextToken()); + line.setOnClickListener(lineHighlighter); + lines.add(line); + } + return lines; + } + + private String getHighlightedSourceCode() { + if (highlightedSourceCode == null) { + highlightedSourceCode = highlightSourceCode(); + } + return highlightedSourceCode; + } + + private String highlightSourceCode() { + String code = replaceTabs(); + if (ApplicationSettings.highlightSources()) { + return SYNTAX_HIGHLIGHTER.highlight(code, language); + } else { + return code; + } + } + + private String replaceTabs() { + StringBuilder tabReplacement = new StringBuilder(); + for (int i = 0; i < ApplicationSettings.getTabSize(); i++) { + tabReplacement.append(" "); + } + return sourceCode.replace("\t", tabReplacement.toString()); + } + + public String getIdentifier() { + return identifier; + } + + public void addTextComment(String comment) throws CommentNotAddedException { + if (selectedLine == null) { + throw new NoSelectedLineException(); + } + getSelectedLine().addTextComment(comment); + } + + public void addVoiceComment(File recordedFile) throws CommentNotAddedException { + if (selectedLine == null) { + throw new NoSelectedLineException(); + } + getSelectedLine().createVoiceComment(recordedFile); + } + + public Line getSelectedLine() { + return selectedLine; + } + + public void markConversation(Line line) { + // Nothing to do, it's perfect. + } + + public static SourceFile createFromString(String sourceCode, String language) { + return new SourceFile(sourceCode, language); + } + + /** + * Creates source file based on a file reference. + */ + public static SourceFile createFromFile(File sourceFile) throws IOException { + String sourceCode = FileUtils.read(sourceFile); + return createFromString(sourceCode, FileUtils.getExtension(sourceFile.getName())); + } +}