Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add text case changing functionality (Fixes #2390) #2426

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,26 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) {
}, 250);
return true;
}
case R.id.action_toggle_case:
if (_hlEditor != null) {
_hlEditor.toggleCase();
}
return true;
case R.id.action_switch_case:
if (_hlEditor != null) {
_hlEditor.switchCase();
}
return true;
case R.id.action_capitalize_words:
if (_hlEditor != null) {
_hlEditor.capitalizeWords();
}
return true;
case R.id.action_capitalize_sentences:
if (_hlEditor != null) {
_hlEditor.capitalizeSentences();
}
return true;
default: {
return super.onOptionsItemSelected(item);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
import net.gsantner.opoc.format.GsTextUtils;
import net.gsantner.opoc.wrapper.GsCallback;
import net.gsantner.opoc.wrapper.GsTextWatcherAdapter;
import net.gsantner.markor.util.TextCasingUtils;

import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
Expand Down Expand Up @@ -297,6 +299,60 @@ private int rowEnd(final int y) {
return layout.getLineEnd(line);
}

// Text-Casing
// ---------------------------------------------------------------------------------------------
public void toggleCase() {
String text = getSelectedText();
if (text.isEmpty()) {
text = Objects.requireNonNull(getText()).toString();
}
String newText = TextCasingUtils.toggleCase(text);
replaceSelection(newText);
}

public void switchCase() {
String text = getSelectedText();
if (text.isEmpty()) {
text = Objects.requireNonNull(getText()).toString();
}
String newText = TextCasingUtils.switchCase(text);
replaceSelection(newText);
}

public void capitalizeWords() {
String text = getSelectedText();
if (text.isEmpty()) {
text = Objects.requireNonNull(getText()).toString();
}
String newText = TextCasingUtils.capitalizeWords(text);
replaceSelection(newText);
}

public void capitalizeSentences() {
String text = getSelectedText();
if (text.isEmpty()) {
text = Objects.requireNonNull(getText()).toString();
}
String newText = TextCasingUtils.capitalizeSentences(text);
replaceSelection(newText);
}

private String getSelectedText() {
int start = Math.max(0, getSelectionStart());
int end = Math.max(0, getSelectionEnd());
return Objects.requireNonNull(getText()).toString().substring(start, end);
}

private void replaceSelection(String replacement) {
int start = Math.max(0, getSelectionStart());
int end = Math.max(0, getSelectionEnd());
if (start == end) { // If no selection is made, replace all the text in the document
setText(replacement);
} else { // Replace only the selected text
Objects.requireNonNull(getText()).replace(start, end, replacement);
}
}

// Various overrides
// ---------------------------------------------------------------------------------------------
public void setSaveInstanceState(final boolean save) {
Expand Down
61 changes: 61 additions & 0 deletions app/src/main/java/net/gsantner/markor/util/TextCasingUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package net.gsantner.markor.util;

public class TextCasingUtils {
public static String toggleCase(String text) { // Toggle all text to Uppercase or Lowercase
if (text.equals(text.toUpperCase())) {
return text.toLowerCase();
} else {
return text.toUpperCase();
}
}

public static String switchCase(String text) { // Switch the text case of each character
StringBuilder result = new StringBuilder();
for (char c : text.toCharArray()) {
if (Character.isUpperCase(c)) {
result.append(Character.toLowerCase(c));
} else if (Character.isLowerCase(c)) {
result.append(Character.toUpperCase(c));
} else {
result.append(c);
}
}
return result.toString();
}

public static String capitalizeWords(String text) { // Capitalize the first letter of each word
StringBuilder result = new StringBuilder();
boolean capitalizeNext = true;
for (char c : text.toCharArray()) {
if (Character.isWhitespace(c)) {
capitalizeNext = true;
result.append(c);
} else if (capitalizeNext) {
result.append(Character.toUpperCase(c));
capitalizeNext = false;
} else {
result.append(Character.toLowerCase(c));
}
}
return result.toString();
}

public static String capitalizeSentences(String text) { // Capitalize the first letter of each sentence
StringBuilder result = new StringBuilder();
boolean capitalizeNext = true;
for (char c : text.toCharArray()) {
if (c == '.' || c == '!' || c == '?') {
capitalizeNext = true;
result.append(c);
} else if (Character.isWhitespace(c)) {
result.append(c);
} else if (capitalizeNext) {
result.append(Character.toUpperCase(c));
capitalizeNext = false;
} else {
result.append(c);
}
}
return result.toString();
}
}
12 changes: 12 additions & 0 deletions app/src/main/res/drawable/ic_format_text_case_black_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M16.51,3C16.82,3 17.1,3.2 17.21,3.5L22.71,19C22.85,19.39 22.64,19.82 22.25,19.96C21.86,20.1 21.43,19.89 21.29,19.5L19.87,15.5H12.76L11.2,19.52C11.05,19.91 10.62,20.1 10.23,19.95C9.84,19.8 9.65,19.37 9.8,18.98L15.8,3.48C15.91,3.19 16.2,3 16.51,3ZM16.47,5.91L13.34,14H19.34L16.47,5.91Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M5.5,10.5L5.79,10.51C7.75,10.61 8.91,11.74 9,13.56L9,13.76V19.26C9,19.64 8.72,19.95 8.35,20L8.25,20.01C7.87,20.01 7.56,19.73 7.51,19.36L7.5,19.26L7.5,19.16C6.51,19.72 5.6,20.01 4.75,20.01C2.91,20.01 1.5,18.72 1.5,16.76C1.5,15.04 2.69,13.75 4.66,13.52C5.59,13.4 6.54,13.47 7.5,13.73C7.49,12.62 6.94,12.07 5.71,12.01C4.75,11.96 4.07,12.1 3.68,12.37C3.34,12.61 2.87,12.53 2.63,12.19C2.4,11.85 2.48,11.38 2.82,11.15C3.47,10.69 4.37,10.48 5.5,10.5ZM7.5,15.32L7.2,15.23C6.39,15.01 5.6,14.95 4.84,15.04C3.61,15.19 3,15.85 3,16.8C3,17.89 3.71,18.55 4.75,18.55C5.43,18.55 6.27,18.23 7.25,17.58L7.5,17.41V15.32Z"/>
</vector>
25 changes: 25 additions & 0 deletions app/src/main/res/menu/document__edit__menu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,31 @@
android:title="@string/font_size"
app:showAsAction="never" />

<!-- Text Case menu -->
<item
android:id="@+id/action_text_case"
android:icon="@drawable/ic_format_text_case_black_24dp"
android:title="@string/text_case"
app:showAsAction="never">
<menu>
<item
android:id="@+id/action_toggle_case"
android:title="@string/toggle_case" />

<item
android:id="@+id/action_switch_case"
android:title="@string/switch_case" />

<item
android:id="@+id/action_capitalize_words"
android:title="@string/capitalize_words" />

<item
android:id="@+id/action_capitalize_sentences"
android:title="@string/capitalize_sentences" />
</menu>
</item>

<!-- Format menu -->
<item
android:id="@+id/submenu_format_selection"
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -477,4 +477,9 @@ work. If not, see <https://creativecommons.org/publicdomain/zero/1.0/>.
<string name="wont_save_min_length">Files with fewer than %d characters not saved automatically in order to prevent data loss.</string>
<string name="advanced_filtering_help"><![CDATA[<small><a href="https://www.github.com/gsantner/markor/discussions/1940">Advanced filtering syntax</a></small>]]></string>
<string name="filter">Filter</string>
<string name="text_case">Text Case</string>
<string name="toggle_case">Toggle Case (Ex: Case->CASE->case)</string>
<string name="switch_case">Switch Case (Ex: CaSe->cAsE)</string>
<string name="capitalize_words">Capitalize Words (Ex: a note->A Note)</string>
<string name="capitalize_sentences">Capitalize Sentences (Ex: case->Case)</string>
</resources>