Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
721c5f0cdc | ||
|
|
3722d5d28a | ||
|
|
39eca4ceea | ||
|
|
6691b83558 | ||
|
|
341fb4ddad | ||
|
|
eec740a735 | ||
|
|
eb14750c3f | ||
|
|
924d69bdc9 | ||
|
|
4340d3d3d3 | ||
|
|
ee07614fe7 | ||
|
|
713b2d37d6 | ||
|
|
1c1d890f65 | ||
|
|
950699102d | ||
|
|
6b79cdc3d0 | ||
|
|
2569575340 | ||
|
|
a542cb3cb4 |
Generated
+1
-1
@@ -4,7 +4,7 @@
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="testRunner" value="CHOOSE_PER_TEST" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
||||
<option name="modules">
|
||||
|
||||
Generated
+13
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
|
||||
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
+8
-4
@@ -6,10 +6,10 @@ android {
|
||||
compileSdk 34
|
||||
defaultConfig {
|
||||
applicationId "org.exbin.bined.editor.android"
|
||||
minSdk 27
|
||||
minSdk 24
|
||||
targetSdk 34
|
||||
versionCode 5
|
||||
versionName "0.2.1"
|
||||
versionCode 8
|
||||
versionName "0.2.2"
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
}
|
||||
buildTypes {
|
||||
@@ -33,10 +33,14 @@ dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
// implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
compileOnly group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2'
|
||||
// implementation 'com.github.rustamg:file-dialogs:1.0'
|
||||
implementation 'com.github.rustamg:file-dialogs:1.0'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
implementation 'androidx.preference:preference:1.2.1'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
testImplementation 'androidx.test:core:1.6.1'
|
||||
// testImplementation 'androidx.test.ext:junit:1.2.1'
|
||||
testCompileOnly group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
|
||||
// implementation 'org.exbin.bined:bined-core:0.3.0-SNAPSHOT'
|
||||
|
||||
@@ -24,7 +24,7 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.auxiliary.binary_data.EditableBinaryData;
|
||||
|
||||
/**
|
||||
* Binary editor component utilities.
|
||||
* Binary editor utilities.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.exbin.bined;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.Nonnull;
|
||||
import org.exbin.auxiliary.binary_data.BinaryData;
|
||||
|
||||
/**
|
||||
@@ -30,7 +30,7 @@ public interface DataProvider {
|
||||
*
|
||||
* @return binary data
|
||||
*/
|
||||
@Nullable
|
||||
@Nonnull
|
||||
BinaryData getContentData();
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,14 +15,11 @@
|
||||
*/
|
||||
package org.exbin.bined;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
/**
|
||||
* Interface for selection change listener.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface SelectionChangedListener {
|
||||
|
||||
/**
|
||||
|
||||
@@ -598,7 +598,6 @@ public class BasicCodeAreaScrolling {
|
||||
return Optional.of(targetScrollPosition);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public void updateMaximumScrollPosition(long rowsPerDocument, int rowsPerPage, int charactersPerRow, int charactersPerPage, int lastCharOffset, int lastRowOffset) {
|
||||
maximumScrollPosition.reset();
|
||||
if (rowsPerDocument > rowsPerPage) {
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.exbin.bined.basic;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
/**
|
||||
@@ -23,7 +22,6 @@ import javax.annotation.concurrent.Immutable;
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
@Immutable
|
||||
public class ScrollViewDimension {
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ public interface CodeAreaColorGroup {
|
||||
|
||||
/**
|
||||
* Returns unique string identifier.
|
||||
*
|
||||
* <p>
|
||||
* Custom implementations should start with full package name to avoid
|
||||
* collisions.
|
||||
*
|
||||
|
||||
@@ -25,12 +25,12 @@ import javax.annotation.Nonnull;
|
||||
public interface BinaryDataCommand {
|
||||
|
||||
/**
|
||||
* Returns command name.
|
||||
* Returns type of the command.
|
||||
*
|
||||
* @return name
|
||||
* @return command type
|
||||
*/
|
||||
@Nonnull
|
||||
String getName();
|
||||
BinaryDataCommandType getType();
|
||||
|
||||
/**
|
||||
* Performs operation on given document.
|
||||
|
||||
@@ -15,20 +15,10 @@
|
||||
*/
|
||||
package org.exbin.bined.operation;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Command type interface.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
public interface BinaryDataCommandType {
|
||||
|
||||
/**
|
||||
* Returns type name.
|
||||
*
|
||||
* @return type name
|
||||
*/
|
||||
@Nonnull
|
||||
String getName();
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
/**
|
||||
* Interface for compound XBUP editor operation.
|
||||
* Interface for compound operation.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
|
||||
@@ -25,12 +25,12 @@ import javax.annotation.Nonnull;
|
||||
public interface BinaryDataOperation {
|
||||
|
||||
/**
|
||||
* Returns operation name.
|
||||
* Returns type of the operation.
|
||||
*
|
||||
* @return operation name
|
||||
* @return operation type
|
||||
*/
|
||||
@Nonnull
|
||||
String getName();
|
||||
BinaryDataOperationType getType();
|
||||
|
||||
/**
|
||||
* Performs operation.
|
||||
|
||||
@@ -15,20 +15,10 @@
|
||||
*/
|
||||
package org.exbin.bined.operation;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Operation type interface.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
public interface BinaryDataOperationType {
|
||||
|
||||
/**
|
||||
* Returns operation type name.
|
||||
*
|
||||
* @return operation type name
|
||||
*/
|
||||
@Nonnull
|
||||
String getName();
|
||||
}
|
||||
|
||||
@@ -15,14 +15,11 @@
|
||||
*/
|
||||
package org.exbin.bined.operation.undo;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
/**
|
||||
* Code area undo support handler.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface BinaryDataUndoRedoState {
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,35 +2,45 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
|
||||
<application
|
||||
android:name=".ApplicationContext"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/bined"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:targetApi="34">
|
||||
<activity
|
||||
android:name=".SettingsActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_settings" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.intent.action.EDIT" />
|
||||
|
||||
<category android:name="android.intent.category.OPENABLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:scheme="file" />
|
||||
<data android:scheme="content" />
|
||||
|
||||
<data android:host="*" />
|
||||
<data android:mimeType="*/*" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".SettingsActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_settings" />
|
||||
</application>
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
|
||||
</manifest>
|
||||
@@ -110,8 +110,11 @@ public class TwoDimensionScrollView extends FrameLayout {
|
||||
// we rely on the fact the View.scrollBy calls scrollTo.
|
||||
if (getChildCount() > 0) {
|
||||
View child = getChildAt(0);
|
||||
x = clamp(x, getWidth() - getPaddingRight() - getPaddingLeft(), child.getWidth());
|
||||
y = clamp(y, getHeight() - getPaddingBottom() - getPaddingTop(), child.getHeight());
|
||||
// TODO For some reason child size resets to zero, disabling this as workaround :-/
|
||||
if (child.getWidth() > 0 && child.getHeight() > 0) {
|
||||
x = clamp(x, getWidth() - getPaddingRight() - getPaddingLeft(), child.getWidth());
|
||||
y = clamp(y, getHeight() - getPaddingBottom() - getPaddingTop(), child.getHeight());
|
||||
}
|
||||
if (x != getScrollX() || y != getScrollY()) {
|
||||
super.scrollTo(x, y);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ import org.exbin.bined.CharsetStreamTranslator;
|
||||
import org.exbin.bined.CodeAreaUtils;
|
||||
import org.exbin.bined.CodeCharactersCase;
|
||||
import org.exbin.bined.CodeType;
|
||||
import org.exbin.bined.android.capability.CharAssessorPainterCapable;
|
||||
import org.exbin.bined.android.capability.ColorAssessorPainterCapable;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -119,6 +121,48 @@ public class CodeAreaAndroidUtils {
|
||||
return new Rect(left, top, right, bottom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds specific color assessor if present.
|
||||
*
|
||||
* @param <T> color assessor
|
||||
* @param painter painter
|
||||
* @param assessorClass color assessor class
|
||||
* @return color assessor if present
|
||||
*/
|
||||
@Nullable
|
||||
public static <T extends CodeAreaColorAssessor> T findColorAssessor(ColorAssessorPainterCapable painter, Class<T> assessorClass) {
|
||||
CodeAreaColorAssessor colorAssessor = painter.getColorAssessor();
|
||||
do {
|
||||
if (assessorClass.isInstance(colorAssessor)) {
|
||||
return assessorClass.cast(colorAssessor);
|
||||
}
|
||||
colorAssessor = colorAssessor.getParentColorAssessor().orElse(null);
|
||||
} while (colorAssessor != null);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds specific character assessor if present.
|
||||
*
|
||||
* @param <T> character assessor
|
||||
* @param painter painter
|
||||
* @param assessorClass character assessor class
|
||||
* @return character assessor if present
|
||||
*/
|
||||
@Nullable
|
||||
public static <T extends CodeAreaCharAssessor> T findCharAssessor(CharAssessorPainterCapable painter, Class<T> assessorClass) {
|
||||
CodeAreaCharAssessor charAssessor = painter.getCharAssessor();
|
||||
do {
|
||||
if (assessorClass.isInstance(charAssessor)) {
|
||||
return assessorClass.cast(charAssessor);
|
||||
}
|
||||
charAssessor = charAssessor.getParentCharAssessor().orElse(null);
|
||||
} while (charAssessor != null);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int getMetaMaskDown() {
|
||||
return KeyEvent.META_CTRL_MASK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.android;
|
||||
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.CodeAreaSection;
|
||||
|
||||
/**
|
||||
* Code area character assessor.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface CodeAreaCharAssessor extends CodeAreaPaintAssessor {
|
||||
|
||||
/**
|
||||
* Returns preview character for particular position.
|
||||
*
|
||||
* @param rowDataPosition row data position
|
||||
* @param byteOnRow byte on current row
|
||||
* @param charOnRow character on current row
|
||||
* @param section current section
|
||||
* @return color or null for default color
|
||||
*/
|
||||
char getPreviewCharacter(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section);
|
||||
|
||||
/**
|
||||
* Returns preview character for cursor position.
|
||||
*
|
||||
* @param rowDataPosition row data position
|
||||
* @param byteOnRow byte on current row
|
||||
* @param charOnRow character on current row
|
||||
* @param cursorData cursor data
|
||||
* @param cursorDataLength cursor data length
|
||||
* @param section current section
|
||||
* @return color or null for default color
|
||||
*/
|
||||
char getPreviewCursorCharacter(long rowDataPosition, int byteOnRow, int charOnRow, byte[] cursorData, int cursorDataLength, CodeAreaSection section);
|
||||
|
||||
/**
|
||||
* Returns parent character assessor if present.
|
||||
*
|
||||
* @return character assessor
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<CodeAreaCharAssessor> getParentCharAssessor();
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.android;
|
||||
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.CodeAreaSection;
|
||||
|
||||
/**
|
||||
* Code area color assessor.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface CodeAreaColorAssessor extends CodeAreaPaintAssessor {
|
||||
|
||||
/**
|
||||
* Returns background color for particular code.
|
||||
*
|
||||
* @param rowDataPosition row data position
|
||||
* @param byteOnRow byte on current row
|
||||
* @param charOnRow character on current row
|
||||
* @param section current section
|
||||
* @param inSelection true if in selection
|
||||
* @return color or null for default color
|
||||
*/
|
||||
@Nullable
|
||||
Integer getPositionTextColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section, boolean inSelection);
|
||||
|
||||
/**
|
||||
* Returns background color for particular code.
|
||||
*
|
||||
* @param rowDataPosition row data position
|
||||
* @param byteOnRow byte on current row
|
||||
* @param charOnRow character on current row
|
||||
* @param section current section
|
||||
* @param inSelection true if in selection
|
||||
* @return color or null for default color
|
||||
*/
|
||||
@Nullable
|
||||
Integer getPositionBackgroundColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section, boolean inSelection);
|
||||
|
||||
/**
|
||||
* Returns parent color assessor if present.
|
||||
*
|
||||
* @return color assessor
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<CodeAreaColorAssessor> getParentColorAssessor();
|
||||
}
|
||||
@@ -31,7 +31,7 @@ public interface CodeAreaCommandHandler {
|
||||
/**
|
||||
* Notifies command handler about end of sequence of append-able commands.
|
||||
*/
|
||||
void undoSequenceBreak();
|
||||
void sequenceBreak();
|
||||
|
||||
/**
|
||||
* Keyboard key was pressed.
|
||||
@@ -93,16 +93,6 @@ public interface CodeAreaCommandHandler {
|
||||
*/
|
||||
void paste();
|
||||
|
||||
/**
|
||||
* Expands selection to all data.
|
||||
*/
|
||||
void selectAll();
|
||||
|
||||
/**
|
||||
* Clears data selection.
|
||||
*/
|
||||
void clearSelection();
|
||||
|
||||
/**
|
||||
* Pastes content of clipboard to cursor area analyzing string code.
|
||||
*/
|
||||
@@ -115,6 +105,16 @@ public interface CodeAreaCommandHandler {
|
||||
*/
|
||||
boolean canPaste();
|
||||
|
||||
/**
|
||||
* Expands selection to all data.
|
||||
*/
|
||||
void selectAll();
|
||||
|
||||
/**
|
||||
* Clears data selection.
|
||||
*/
|
||||
void clearSelection();
|
||||
|
||||
/**
|
||||
* Moves caret with mouse event.
|
||||
*
|
||||
|
||||
@@ -50,18 +50,18 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||
public abstract class CodeAreaCore extends ViewGroup implements CodeAreaControl {
|
||||
|
||||
@Nonnull
|
||||
private BinaryData contentData = EmptyBinaryData.INSTANCE;
|
||||
protected BinaryData contentData = EmptyBinaryData.INSTANCE;
|
||||
|
||||
@Nonnull
|
||||
protected final PrimaryView primaryView;
|
||||
|
||||
@Nonnull
|
||||
private CodeAreaCommandHandler commandHandler;
|
||||
protected CodeAreaCommandHandler commandHandler;
|
||||
|
||||
private final List<DataChangedListener> dataChangedListeners = new ArrayList<>();
|
||||
protected final List<DataChangedListener> dataChangedListeners = new ArrayList<>();
|
||||
|
||||
private float touchPositionX;
|
||||
private float touchPositionY;
|
||||
protected float touchPositionX;
|
||||
protected float touchPositionY;
|
||||
|
||||
/**
|
||||
* Creates new instance with default command handler and painter.
|
||||
@@ -88,6 +88,7 @@ public abstract class CodeAreaCore extends ViewGroup implements CodeAreaControl
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setContentDescription("Code area");
|
||||
// TODO: Use swing color instead
|
||||
// setBackgroundColor(ColorUtils.WHITE);
|
||||
// setFocusable(true);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.android;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
/**
|
||||
* Code area paint assessor.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface CodeAreaPaintAssessor {
|
||||
|
||||
/**
|
||||
* Reports start of the paint operation.
|
||||
*
|
||||
* @param codeAreaPaintState paint state
|
||||
*/
|
||||
void startPaint(CodeAreaPaintState codeAreaPaintState);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.android;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.auxiliary.binary_data.BinaryData;
|
||||
import org.exbin.bined.CodeAreaSection;
|
||||
import org.exbin.bined.CodeAreaSelection;
|
||||
import org.exbin.bined.android.basic.color.CodeAreaColorsProfile;
|
||||
|
||||
/**
|
||||
* Code area paint state.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface CodeAreaPaintState {
|
||||
|
||||
@Nonnull
|
||||
CodeAreaSection getActiveSection();
|
||||
|
||||
@Nonnull
|
||||
CodeAreaColorsProfile getColorsProfile();
|
||||
|
||||
@Nonnull
|
||||
Charset getCharset();
|
||||
|
||||
@Nonnull
|
||||
byte[] getRowData();
|
||||
|
||||
int getMaxBytesPerChar();
|
||||
|
||||
int getCodeLastCharPos();
|
||||
|
||||
int getCharactersPerRow();
|
||||
|
||||
int getBytesPerRow();
|
||||
|
||||
long getDataSize();
|
||||
|
||||
// TODO: Replace with row data only?
|
||||
@Nonnull
|
||||
BinaryData getContentData();
|
||||
|
||||
@Nullable
|
||||
CodeAreaSelection getSelectionHandler();
|
||||
}
|
||||
@@ -30,38 +30,31 @@ import org.exbin.bined.basic.BasicCodeAreaZone;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class BasicCodeAreaDimensions {
|
||||
|
||||
private int scrollPanelX;
|
||||
private int scrollPanelY;
|
||||
private int scrollPanelWidth;
|
||||
private int scrollPanelHeight;
|
||||
private int verticalScrollBarSize;
|
||||
private int horizontalScrollBarSize;
|
||||
private int dataViewWidth;
|
||||
private int dataViewHeight;
|
||||
private int lastCharOffset;
|
||||
private int lastRowOffset;
|
||||
protected int scrollPanelX;
|
||||
protected int scrollPanelY;
|
||||
protected int scrollPanelWidth;
|
||||
protected int scrollPanelHeight;
|
||||
protected int verticalScrollBarSize;
|
||||
protected int horizontalScrollBarSize;
|
||||
protected int dataViewWidth;
|
||||
protected int dataViewHeight;
|
||||
protected int lastCharOffset;
|
||||
protected int lastRowOffset;
|
||||
|
||||
private int headerAreaHeight;
|
||||
private int rowPositionAreaWidth;
|
||||
private int rowsPerRect;
|
||||
private int rowsPerPage;
|
||||
private int charactersPerPage;
|
||||
private int charactersPerRect;
|
||||
protected int headerAreaHeight;
|
||||
protected int rowPositionAreaWidth;
|
||||
protected int rowsPerRect;
|
||||
protected int rowsPerPage;
|
||||
protected int charactersPerPage;
|
||||
protected int charactersPerRect;
|
||||
|
||||
@Nonnull
|
||||
private final Rect componentRectangle = new Rect();
|
||||
@Nonnull
|
||||
private final Rect mainAreaRectangle = new Rect();
|
||||
@Nonnull
|
||||
private final Rect headerAreaRectangle = new Rect();
|
||||
@Nonnull
|
||||
private final Rect rowPositionAreaRectangle = new Rect();
|
||||
@Nonnull
|
||||
private final Rect scrollPanelRectangle = new Rect();
|
||||
@Nonnull
|
||||
private final Rect dataViewRectangle = new Rect();
|
||||
@Nonnull
|
||||
private final Rect dataViewInnerRectangle = new Rect();
|
||||
protected final Rect componentRectangle = new Rect();
|
||||
protected final Rect mainAreaRectangle = new Rect();
|
||||
protected final Rect headerAreaRectangle = new Rect();
|
||||
protected final Rect rowPositionAreaRectangle = new Rect();
|
||||
protected final Rect scrollPanelRectangle = new Rect();
|
||||
protected final Rect dataViewRectangle = new Rect();
|
||||
protected final Rect dataViewInnerRectangle = new Rect();
|
||||
|
||||
public void recomputeSizes(BasicCodeAreaMetrics metrics, int componentX, int componentY, int componentWidth, int componentHeight, int rowPositionLength, int verticalScrollBarSize, int horizontalScrollBarSize) {
|
||||
modifyRect(componentRectangle, componentX, componentY, componentWidth, componentHeight);
|
||||
|
||||
@@ -34,14 +34,14 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||
public class BasicCodeAreaMetrics {
|
||||
|
||||
@Nullable
|
||||
private Paint fontMetrics;
|
||||
private boolean monospaceFont;
|
||||
protected Paint fontMetrics;
|
||||
protected boolean monospaceFont;
|
||||
|
||||
private int rowHeight;
|
||||
private int characterWidth;
|
||||
private int fontHeight;
|
||||
private int maxBytesPerChar;
|
||||
private int subFontSpace = 0;
|
||||
protected int rowHeight;
|
||||
protected int characterWidth;
|
||||
protected int fontHeight;
|
||||
protected int maxBytesPerChar;
|
||||
protected int subFontSpace = 0;
|
||||
|
||||
public void recomputeMetrics(@Nullable Paint fontMetrics, Charset charset) {
|
||||
this.fontMetrics = fontMetrics;
|
||||
@@ -57,7 +57,7 @@ public class BasicCodeAreaMetrics {
|
||||
*/
|
||||
characterWidth = (int) fontMetrics.measureText("w");
|
||||
int fontSize = (int) fontMetrics.getTextSize();
|
||||
subFontSpace = rowHeight - fontSize + 4;
|
||||
subFontSpace = (rowHeight / 6);
|
||||
|
||||
/*
|
||||
* Compare it to small 'i' to detect if font is monospaced.
|
||||
|
||||
@@ -30,22 +30,22 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class BasicCodeAreaVisibility {
|
||||
|
||||
private int splitLinePos;
|
||||
protected int splitLinePos;
|
||||
|
||||
private int skipToCode;
|
||||
private int skipToChar;
|
||||
private int skipToPreview;
|
||||
private int skipRestFromCode;
|
||||
private int skipRestFromChar;
|
||||
private int skipRestFromPreview;
|
||||
protected int skipToCode;
|
||||
protected int skipToChar;
|
||||
protected int skipToPreview;
|
||||
protected int skipRestFromCode;
|
||||
protected int skipRestFromChar;
|
||||
protected int skipRestFromPreview;
|
||||
|
||||
private boolean codeSectionVisible;
|
||||
private boolean previewSectionVisible;
|
||||
protected boolean codeSectionVisible;
|
||||
protected boolean previewSectionVisible;
|
||||
|
||||
private int charactersPerCodeSection;
|
||||
private int codeLastCharPos;
|
||||
private int previewCharPos;
|
||||
private int previewRelativeX;
|
||||
protected int charactersPerCodeSection;
|
||||
protected int codeLastCharPos;
|
||||
protected int previewCharPos;
|
||||
protected int previewRelativeX;
|
||||
|
||||
public void recomputeCharPositions(BasicCodeAreaMetrics metrics, BasicCodeAreaStructure structure, BasicCodeAreaDimensions dimensions, BasicCodeAreaLayout layout, BasicCodeAreaScrolling scrolling) {
|
||||
int bytesPerRow = structure.getBytesPerRow();
|
||||
|
||||
@@ -74,55 +74,53 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||
public class CodeArea extends CodeAreaCore implements DefaultCodeArea, CodeAreaAndroidControl {
|
||||
|
||||
@Nonnull
|
||||
private CodeAreaPainter painter;
|
||||
protected CodeAreaPainter painter;
|
||||
|
||||
@Nonnull
|
||||
private final DefaultCodeAreaCaret codeAreaCaret;
|
||||
@Nonnull
|
||||
private final CodeAreaSelection selection = new CodeAreaSelection();
|
||||
@Nonnull
|
||||
private final CodeAreaScrollPosition scrollPosition = new CodeAreaScrollPosition();
|
||||
protected final DefaultCodeAreaCaret codeAreaCaret;
|
||||
protected final CodeAreaSelection selection = new CodeAreaSelection();
|
||||
protected final CodeAreaScrollPosition scrollPosition = new CodeAreaScrollPosition();
|
||||
|
||||
@Nonnull
|
||||
private Charset charset = Charset.forName(CodeAreaAndroidUtils.DEFAULT_ENCODING);
|
||||
protected Charset charset = Charset.forName(CodeAreaAndroidUtils.DEFAULT_ENCODING);
|
||||
@Nonnull
|
||||
private ClipboardHandlingMode clipboardHandlingMode = ClipboardHandlingMode.PROCESS;
|
||||
protected ClipboardHandlingMode clipboardHandlingMode = ClipboardHandlingMode.PROCESS;
|
||||
|
||||
@Nonnull
|
||||
private EditMode editMode = EditMode.EXPANDING;
|
||||
protected EditMode editMode = EditMode.EXPANDING;
|
||||
@Nonnull
|
||||
private EditOperation editOperation = EditOperation.OVERWRITE;
|
||||
protected EditOperation editOperation = EditOperation.OVERWRITE;
|
||||
@Nonnull
|
||||
private CodeAreaViewMode viewMode = CodeAreaViewMode.DUAL;
|
||||
protected CodeAreaViewMode viewMode = CodeAreaViewMode.DUAL;
|
||||
@Nullable
|
||||
private Font codeFont;
|
||||
protected Font codeFont;
|
||||
@Nonnull
|
||||
private BasicBackgroundPaintMode backgroundPaintMode = BasicBackgroundPaintMode.STRIPED;
|
||||
protected BasicBackgroundPaintMode backgroundPaintMode = BasicBackgroundPaintMode.STRIPED;
|
||||
@Nonnull
|
||||
private CodeType codeType = CodeType.HEXADECIMAL;
|
||||
protected CodeType codeType = CodeType.HEXADECIMAL;
|
||||
@Nonnull
|
||||
private CodeCharactersCase codeCharactersCase = CodeCharactersCase.UPPER;
|
||||
private boolean showMirrorCursor = true;
|
||||
protected CodeCharactersCase codeCharactersCase = CodeCharactersCase.UPPER;
|
||||
protected boolean showMirrorCursor = true;
|
||||
@Nonnull
|
||||
private RowWrappingMode rowWrapping = RowWrappingMode.NO_WRAPPING;
|
||||
private int minRowPositionLength = 0;
|
||||
private int maxRowPositionLength = 0;
|
||||
private int wrappingBytesGroupSize = 0;
|
||||
private int maxBytesPerRow = 16;
|
||||
protected RowWrappingMode rowWrapping = RowWrappingMode.NO_WRAPPING;
|
||||
protected int minRowPositionLength = 0;
|
||||
protected int maxRowPositionLength = 0;
|
||||
protected int wrappingBytesGroupSize = 0;
|
||||
protected int maxBytesPerRow = 16;
|
||||
|
||||
@Nonnull
|
||||
private ScrollBarVisibility verticalScrollBarVisibility = ScrollBarVisibility.IF_NEEDED;
|
||||
protected ScrollBarVisibility verticalScrollBarVisibility = ScrollBarVisibility.IF_NEEDED;
|
||||
@Nonnull
|
||||
private VerticalScrollUnit verticalScrollUnit = VerticalScrollUnit.PIXEL;
|
||||
protected VerticalScrollUnit verticalScrollUnit = VerticalScrollUnit.PIXEL;
|
||||
@Nonnull
|
||||
private ScrollBarVisibility horizontalScrollBarVisibility = ScrollBarVisibility.IF_NEEDED;
|
||||
protected ScrollBarVisibility horizontalScrollBarVisibility = ScrollBarVisibility.IF_NEEDED;
|
||||
@Nonnull
|
||||
private HorizontalScrollUnit horizontalScrollUnit = HorizontalScrollUnit.PIXEL;
|
||||
protected HorizontalScrollUnit horizontalScrollUnit = HorizontalScrollUnit.PIXEL;
|
||||
|
||||
private final List<CodeAreaCaretListener> caretMovedListeners = new ArrayList<>();
|
||||
private final List<ScrollingListener> scrollingListeners = new ArrayList<>();
|
||||
private final List<SelectionChangedListener> selectionChangedListeners = new ArrayList<>();
|
||||
private final List<EditModeChangedListener> editModeChangedListeners = new ArrayList<>();
|
||||
protected final List<CodeAreaCaretListener> caretMovedListeners = new ArrayList<>();
|
||||
protected final List<ScrollingListener> scrollingListeners = new ArrayList<>();
|
||||
protected final List<SelectionChangedListener> selectionChangedListeners = new ArrayList<>();
|
||||
protected final List<EditModeChangedListener> editModeChangedListeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates new instance with default command handler and painter.
|
||||
|
||||
@@ -37,19 +37,19 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class DefaultCodeAreaCaret implements CodeAreaCaret {
|
||||
|
||||
private static final int DOUBLE_CURSOR_WIDTH = 2;
|
||||
private static final int DEFAULT_BLINK_RATE = 450;
|
||||
protected static final int DOUBLE_CURSOR_WIDTH = 2;
|
||||
protected static final int DEFAULT_BLINK_RATE = 450;
|
||||
|
||||
@Nonnull
|
||||
private final CaretChangeListener changeListener;
|
||||
private final DefaultCodeAreaCaretPosition caretPosition = new DefaultCodeAreaCaretPosition();
|
||||
protected final CaretChangeListener changeListener;
|
||||
protected final DefaultCodeAreaCaretPosition caretPosition = new DefaultCodeAreaCaretPosition();
|
||||
|
||||
private int blinkRate = 0;
|
||||
private Timer blinkTimer = null;
|
||||
private boolean cursorVisible = true;
|
||||
protected int blinkRate = 0;
|
||||
protected Timer blinkTimer = null;
|
||||
protected boolean cursorVisible = true;
|
||||
|
||||
@Nonnull
|
||||
private CursorRenderingMode renderingMode = CursorRenderingMode.NEGATIVE;
|
||||
protected CursorRenderingMode renderingMode = CursorRenderingMode.NEGATIVE;
|
||||
|
||||
public DefaultCodeAreaCaret(CaretChangeListener changeListener) {
|
||||
CodeAreaUtils.requireNonNull(changeListener, "Change listener cannot be null");
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.android.basic;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.CodeAreaSection;
|
||||
import org.exbin.bined.android.CodeAreaCharAssessor;
|
||||
import org.exbin.bined.android.CodeAreaPaintState;
|
||||
|
||||
/**
|
||||
* Default code area character assessor.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class DefaultCodeAreaCharAssessor implements CodeAreaCharAssessor {
|
||||
|
||||
protected final CodeAreaCharAssessor parentCharAssessor;
|
||||
|
||||
@Nullable
|
||||
protected Charset charMappingCharset = null;
|
||||
@Nonnull
|
||||
protected final char[] charMapping = new char[256];
|
||||
|
||||
protected long dataSize;
|
||||
protected int maxBytesPerChar;
|
||||
protected byte[] rowData;
|
||||
protected Charset charset;
|
||||
|
||||
public DefaultCodeAreaCharAssessor() {
|
||||
parentCharAssessor = null;
|
||||
}
|
||||
|
||||
public DefaultCodeAreaCharAssessor(@Nullable CodeAreaCharAssessor parentCharAssessor) {
|
||||
this.parentCharAssessor = parentCharAssessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPaint(CodeAreaPaintState codeAreaPaintState) {
|
||||
dataSize = codeAreaPaintState.getDataSize();
|
||||
charset = codeAreaPaintState.getCharset();
|
||||
rowData = codeAreaPaintState.getRowData();
|
||||
maxBytesPerChar = codeAreaPaintState.getMaxBytesPerChar();
|
||||
|
||||
|
||||
if (parentCharAssessor != null) {
|
||||
parentCharAssessor.startPaint(codeAreaPaintState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getPreviewCharacter(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section) {
|
||||
if (maxBytesPerChar > 1) {
|
||||
if (rowDataPosition + maxBytesPerChar > dataSize) {
|
||||
maxBytesPerChar = (int) (dataSize - rowDataPosition);
|
||||
}
|
||||
|
||||
int charDataLength = maxBytesPerChar;
|
||||
if (byteOnRow + charDataLength > rowData.length) {
|
||||
charDataLength = rowData.length - byteOnRow;
|
||||
}
|
||||
String displayString = new String(rowData, byteOnRow, charDataLength, charset);
|
||||
if (!displayString.isEmpty()) {
|
||||
return displayString.charAt(0);
|
||||
}
|
||||
} else {
|
||||
if (charMappingCharset == null || charMappingCharset != charset) {
|
||||
buildCharMapping(charset);
|
||||
}
|
||||
|
||||
return charMapping[rowData[byteOnRow] & 0xFF];
|
||||
}
|
||||
|
||||
if (parentCharAssessor != null) {
|
||||
return parentCharAssessor.getPreviewCharacter(rowDataPosition, byteOnRow, charOnRow, section);
|
||||
}
|
||||
|
||||
return ' ';
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getPreviewCursorCharacter(long rowDataPosition, int byteOnRow, int charOnRow, byte[] cursorData, int cursorDataLength, CodeAreaSection section) {
|
||||
if (cursorDataLength == 0) {
|
||||
return ' ';
|
||||
}
|
||||
|
||||
if (maxBytesPerChar > 1) {
|
||||
String displayString = new String(cursorData, 0, cursorDataLength, charset);
|
||||
if (!displayString.isEmpty()) {
|
||||
return displayString.charAt(0);
|
||||
}
|
||||
} else {
|
||||
if (charMappingCharset == null || charMappingCharset != charset) {
|
||||
buildCharMapping(charset);
|
||||
}
|
||||
|
||||
return charMapping[cursorData[0] & 0xFF];
|
||||
}
|
||||
|
||||
if (parentCharAssessor != null) {
|
||||
return parentCharAssessor.getPreviewCursorCharacter(rowDataPosition, byteOnRow, charOnRow, cursorData, cursorDataLength, section);
|
||||
}
|
||||
|
||||
return ' ';
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Optional<CodeAreaCharAssessor> getParentCharAssessor() {
|
||||
return Optional.ofNullable(parentCharAssessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Precomputes widths for basic ascii characters.
|
||||
*
|
||||
* @param charset character set
|
||||
*/
|
||||
private void buildCharMapping(Charset charset) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
charMapping[i] = new String(new byte[]{(byte) i}, charset).charAt(0);
|
||||
}
|
||||
charMappingCharset = charset;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.android.basic;
|
||||
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.CodeAreaSection;
|
||||
import org.exbin.bined.basic.BasicCodeAreaSection;
|
||||
import org.exbin.bined.color.CodeAreaBasicColors;
|
||||
import org.exbin.bined.android.CodeAreaPaintState;
|
||||
import org.exbin.bined.android.CodeAreaColorAssessor;
|
||||
import org.exbin.bined.android.basic.color.CodeAreaColorsProfile;
|
||||
|
||||
/**
|
||||
* Default code area color assessor.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class DefaultCodeAreaColorAssessor implements CodeAreaColorAssessor {
|
||||
|
||||
protected final CodeAreaColorAssessor parentColorAssessor;
|
||||
|
||||
protected CodeAreaSection activeSection = null;
|
||||
protected int codeLastCharPos;
|
||||
protected Integer selectionColor;
|
||||
protected Integer selectionMirrorColor;
|
||||
protected Integer selectionBackground;
|
||||
protected Integer selectionMirrorBackground;
|
||||
|
||||
public DefaultCodeAreaColorAssessor() {
|
||||
parentColorAssessor = null;
|
||||
}
|
||||
|
||||
public DefaultCodeAreaColorAssessor(@Nullable CodeAreaColorAssessor parentColorAssessor) {
|
||||
this.parentColorAssessor = parentColorAssessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPaint(CodeAreaPaintState codeAreaPainterState) {
|
||||
activeSection = codeAreaPainterState.getActiveSection();
|
||||
codeLastCharPos = codeAreaPainterState.getCodeLastCharPos();
|
||||
CodeAreaColorsProfile colorsProfile = codeAreaPainterState.getColorsProfile();
|
||||
selectionColor = colorsProfile.getColor(CodeAreaBasicColors.SELECTION_COLOR);
|
||||
selectionMirrorColor = colorsProfile.getColor(CodeAreaBasicColors.SELECTION_MIRROR_COLOR);
|
||||
selectionBackground = colorsProfile.getColor(CodeAreaBasicColors.SELECTION_BACKGROUND);
|
||||
selectionMirrorBackground = colorsProfile.getColor(CodeAreaBasicColors.SELECTION_MIRROR_BACKGROUND);
|
||||
|
||||
if (parentColorAssessor != null) {
|
||||
parentColorAssessor.startPaint(codeAreaPainterState);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer getPositionTextColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section, boolean inSelection) {
|
||||
if (inSelection) {
|
||||
return section == activeSection ? selectionColor : selectionMirrorColor;
|
||||
}
|
||||
|
||||
if (parentColorAssessor != null) {
|
||||
return parentColorAssessor.getPositionTextColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer getPositionBackgroundColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section, boolean inSelection) {
|
||||
if (inSelection && (section == BasicCodeAreaSection.CODE_MATRIX)) {
|
||||
if (charOnRow == codeLastCharPos) {
|
||||
inSelection = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (inSelection) {
|
||||
return section == activeSection ? selectionBackground : selectionMirrorBackground;
|
||||
}
|
||||
|
||||
if (parentColorAssessor != null) {
|
||||
return parentColorAssessor.getPositionBackgroundColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Optional<CodeAreaColorAssessor> getParentColorAssessor() {
|
||||
return Optional.ofNullable(parentColorAssessor);
|
||||
}
|
||||
}
|
||||
+15
-18
@@ -20,10 +20,7 @@ import android.content.ClipDescription;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import org.exbin.auxiliary.binary_data.ByteArrayData;
|
||||
@@ -141,7 +138,7 @@ public class DefaultCodeAreaCommandHandler implements CodeAreaCommandHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undoSequenceBreak() {
|
||||
public void sequenceBreak() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@@ -154,28 +151,28 @@ public class DefaultCodeAreaCommandHandler implements CodeAreaCommandHandler {
|
||||
switch (keyEvent.getKeyCode()) {
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT: {
|
||||
move(isSelectingMode(keyEvent), MovementDirection.LEFT);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
}
|
||||
case KeyEvent.KEYCODE_DPAD_RIGHT: {
|
||||
move(isSelectingMode(keyEvent), MovementDirection.RIGHT);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
}
|
||||
case KeyEvent.KEYCODE_DPAD_UP: {
|
||||
move(isSelectingMode(keyEvent), MovementDirection.UP);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
}
|
||||
case KeyEvent.KEYCODE_DPAD_DOWN: {
|
||||
move(isSelectingMode(keyEvent), MovementDirection.DOWN);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
@@ -186,7 +183,7 @@ public class DefaultCodeAreaCommandHandler implements CodeAreaCommandHandler {
|
||||
} else {
|
||||
move(isSelectingMode(keyEvent), MovementDirection.ROW_START);
|
||||
}
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
@@ -197,7 +194,7 @@ public class DefaultCodeAreaCommandHandler implements CodeAreaCommandHandler {
|
||||
} else {
|
||||
move(isSelectingMode(keyEvent), MovementDirection.ROW_END);
|
||||
}
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
@@ -205,7 +202,7 @@ public class DefaultCodeAreaCommandHandler implements CodeAreaCommandHandler {
|
||||
case KeyEvent.KEYCODE_PAGE_UP: {
|
||||
scroll(ScrollingDirection.PAGE_UP);
|
||||
move(isSelectingMode(keyEvent), MovementDirection.PAGE_UP);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
@@ -213,7 +210,7 @@ public class DefaultCodeAreaCommandHandler implements CodeAreaCommandHandler {
|
||||
case KeyEvent.KEYCODE_PAGE_DOWN: {
|
||||
scroll(ScrollingDirection.PAGE_DOWN);
|
||||
move(isSelectingMode(keyEvent), MovementDirection.PAGE_DOWN);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
}
|
||||
@@ -320,7 +317,7 @@ public class DefaultCodeAreaCommandHandler implements CodeAreaCommandHandler {
|
||||
EditMode editMode = ((EditModeCapable) codeArea).getEditMode();
|
||||
if (codeArea.hasSelection() && editMode != EditMode.INPLACE) {
|
||||
deleteSelection();
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
}
|
||||
|
||||
int value;
|
||||
@@ -392,7 +389,7 @@ public class DefaultCodeAreaCommandHandler implements CodeAreaCommandHandler {
|
||||
}
|
||||
}
|
||||
if (codeArea.hasSelection() && editMode != EditMode.INPLACE) {
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
deleteSelection();
|
||||
}
|
||||
|
||||
@@ -456,7 +453,7 @@ public class DefaultCodeAreaCommandHandler implements CodeAreaCommandHandler {
|
||||
if (tabKeyHandlingMode == TabKeyHandlingMode.PLATFORM_SPECIFIC || tabKeyHandlingMode == TabKeyHandlingMode.CYCLE_TO_NEXT_SECTION || tabKeyHandlingMode == TabKeyHandlingMode.CYCLE_TO_PREVIOUS_SECTION) {
|
||||
if (viewModeSupported && ((ViewModeCapable) codeArea).getViewMode() == CodeAreaViewMode.DUAL) {
|
||||
move(selectingMode, MovementDirection.SWITCH_SECTION);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
}
|
||||
} else if (((CaretCapable) codeArea).getActiveSection() == BasicCodeAreaSection.TEXT_PREVIEW) {
|
||||
@@ -715,7 +712,7 @@ public class DefaultCodeAreaCommandHandler implements CodeAreaCommandHandler {
|
||||
|
||||
caret.setCodeOffset(0);
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(caret.getCaretPosition());
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
codeArea.notifyDataChanged();
|
||||
revealCursor();
|
||||
clearSelection();
|
||||
@@ -785,7 +782,7 @@ public class DefaultCodeAreaCommandHandler implements CodeAreaCommandHandler {
|
||||
|
||||
caret.setCodeOffset(0);
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(caret.getCaretPosition());
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
codeArea.notifyDataChanged();
|
||||
revealCursor();
|
||||
clearSelection();
|
||||
@@ -853,7 +850,7 @@ public class DefaultCodeAreaCommandHandler implements CodeAreaCommandHandler {
|
||||
((CaretCapable) codeArea).getCodeAreaCaret().setCaretPosition(caretPosition);
|
||||
updateSelection(selecting, caretPosition);
|
||||
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
codeArea.repaint();
|
||||
}
|
||||
|
||||
|
||||
@@ -34,13 +34,13 @@ public class DefaultCodeAreaMouseListener implements View.OnTouchListener, View.
|
||||
|
||||
public static final int MOUSE_SCROLL_LINES = 3;
|
||||
|
||||
private final CodeAreaCore codeArea;
|
||||
private final DefaultCodeAreaScrollPane view;
|
||||
protected final CodeAreaCore codeArea;
|
||||
protected final DefaultCodeAreaScrollPane view;
|
||||
|
||||
private final int defaultCursor = 0;
|
||||
private final int textCursor = 1;
|
||||
private int currentCursor;
|
||||
private boolean menuShown = false;
|
||||
protected final int defaultCursor = 0;
|
||||
protected final int textCursor = 1;
|
||||
protected int currentCursor;
|
||||
protected boolean menuShown = false;
|
||||
|
||||
public DefaultCodeAreaMouseListener(CodeAreaCore codeArea, DefaultCodeAreaScrollPane view) {
|
||||
this.codeArea = codeArea;
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.exbin.bined.android.basic;
|
||||
import android.app.Activity;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.DashPathEffect;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
@@ -42,11 +43,17 @@ import org.exbin.bined.DefaultCodeAreaCaretPosition;
|
||||
import org.exbin.bined.EditOperation;
|
||||
import org.exbin.bined.PositionCodeType;
|
||||
import org.exbin.bined.android.CodeAreaAndroidUtils;
|
||||
import org.exbin.bined.android.CodeAreaCharAssessor;
|
||||
import org.exbin.bined.android.CodeAreaColorAssessor;
|
||||
import org.exbin.bined.android.CodeAreaCore;
|
||||
import org.exbin.bined.android.CodeAreaPaintState;
|
||||
import org.exbin.bined.android.CodeAreaPainter;
|
||||
import org.exbin.bined.android.Font;
|
||||
import org.exbin.bined.android.basic.color.BasicCodeAreaColorsProfile;
|
||||
import org.exbin.bined.android.basic.color.BasicColorsCapableCodeAreaPainter;
|
||||
import org.exbin.bined.android.basic.color.CodeAreaColorsProfile;
|
||||
import org.exbin.bined.android.capability.CharAssessorPainterCapable;
|
||||
import org.exbin.bined.android.capability.ColorAssessorPainterCapable;
|
||||
import org.exbin.bined.android.capability.FontCapable;
|
||||
import org.exbin.bined.basic.BasicBackgroundPaintMode;
|
||||
import org.exbin.bined.basic.BasicCodeAreaLayout;
|
||||
@@ -84,80 +91,77 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapableCodeAreaPainter {
|
||||
public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapableCodeAreaPainter, CodeAreaPaintState, ColorAssessorPainterCapable, CharAssessorPainterCapable {
|
||||
|
||||
@Nonnull
|
||||
protected final CodeAreaCore codeArea;
|
||||
private volatile boolean initialized = false;
|
||||
private volatile boolean adjusting = false;
|
||||
protected volatile boolean initialized = false;
|
||||
protected volatile boolean adjusting = false;
|
||||
|
||||
private volatile boolean fontChanged = false;
|
||||
private volatile boolean layoutChanged = true;
|
||||
private volatile boolean resetColors = true;
|
||||
private volatile boolean caretChanged = true;
|
||||
protected volatile boolean fontChanged = false;
|
||||
protected volatile boolean layoutChanged = true;
|
||||
protected volatile boolean resetColors = true;
|
||||
protected volatile boolean caretChanged = true;
|
||||
|
||||
@Nullable
|
||||
private Paint paint = null;
|
||||
protected Paint paint = null;
|
||||
@Nonnull
|
||||
private final View dataView;
|
||||
protected final View dataView;
|
||||
@Nonnull
|
||||
private final DefaultCodeAreaScrollPane scrollPanel;
|
||||
protected final DefaultCodeAreaScrollPane scrollPanel;
|
||||
@Nonnull
|
||||
private final DefaultCodeAreaMouseListener codeAreaMouseListener;
|
||||
protected final DefaultCodeAreaMouseListener codeAreaMouseListener;
|
||||
|
||||
private int dataViewOffsetX = 0;
|
||||
private int dataViewOffsetY = 0;
|
||||
private int scrollOffsetX = 0;
|
||||
private int scrollOffsetY = 0;
|
||||
protected int dataViewOffsetX = 0;
|
||||
protected int dataViewOffsetY = 0;
|
||||
protected int scrollOffsetX = 0;
|
||||
protected int scrollOffsetY = 0;
|
||||
|
||||
@Nonnull
|
||||
private final DataChangedListener codeAreaDataChangeListener;
|
||||
protected final DataChangedListener codeAreaDataChangeListener;
|
||||
|
||||
@Nonnull
|
||||
private final BasicCodeAreaMetrics metrics = new BasicCodeAreaMetrics();
|
||||
@Nonnull
|
||||
private final BasicCodeAreaStructure structure = new BasicCodeAreaStructure();
|
||||
@Nonnull
|
||||
private final BasicCodeAreaScrolling scrolling = new BasicCodeAreaScrolling();
|
||||
@Nonnull
|
||||
private final BasicCodeAreaDimensions dimensions = new BasicCodeAreaDimensions();
|
||||
@Nonnull
|
||||
private final BasicCodeAreaVisibility visibility = new BasicCodeAreaVisibility();
|
||||
protected final BasicCodeAreaMetrics metrics = new BasicCodeAreaMetrics();
|
||||
protected final BasicCodeAreaStructure structure = new BasicCodeAreaStructure();
|
||||
protected final BasicCodeAreaScrolling scrolling = new BasicCodeAreaScrolling();
|
||||
protected final BasicCodeAreaDimensions dimensions = new BasicCodeAreaDimensions();
|
||||
protected final BasicCodeAreaVisibility visibility = new BasicCodeAreaVisibility();
|
||||
|
||||
protected final BasicCodeAreaLayout layout = new BasicCodeAreaLayout();
|
||||
@Nonnull
|
||||
private final BasicCodeAreaLayout layout = new BasicCodeAreaLayout();
|
||||
@Nonnull
|
||||
private BasicCodeAreaColorsProfile colorsProfile = new BasicCodeAreaColorsProfile();
|
||||
protected BasicCodeAreaColorsProfile colorsProfile = new BasicCodeAreaColorsProfile();
|
||||
|
||||
@Nullable
|
||||
private CodeCharactersCase codeCharactersCase;
|
||||
protected CodeCharactersCase codeCharactersCase;
|
||||
@Nullable
|
||||
private EditOperation editOperation;
|
||||
protected EditOperation editOperation;
|
||||
@Nullable
|
||||
private BasicBackgroundPaintMode backgroundPaintMode;
|
||||
private boolean showMirrorCursor;
|
||||
protected BasicBackgroundPaintMode backgroundPaintMode;
|
||||
protected boolean showMirrorCursor;
|
||||
|
||||
private int rowPositionLength;
|
||||
private int minRowPositionLength;
|
||||
private int maxRowPositionLength;
|
||||
protected int rowPositionLength;
|
||||
protected int minRowPositionLength;
|
||||
protected int maxRowPositionLength;
|
||||
|
||||
@Nullable
|
||||
private Font font;
|
||||
protected Font font;
|
||||
@Nonnull
|
||||
private Charset charset;
|
||||
protected Charset charset;
|
||||
@Nonnull
|
||||
protected CodeAreaColorAssessor colorAssessor = null;
|
||||
@Nonnull
|
||||
protected CodeAreaCharAssessor charAssessor = null;
|
||||
|
||||
@Nullable
|
||||
private RowDataCache rowDataCache = null;
|
||||
protected RowDataCache rowDataCache = null;
|
||||
@Nullable
|
||||
private CursorDataCache cursorDataCache = null;
|
||||
|
||||
@Nullable
|
||||
private Charset charMappingCharset = null;
|
||||
private final char[] charMapping = new char[256];
|
||||
protected CursorDataCache cursorDataCache = null;
|
||||
|
||||
public DefaultCodeAreaPainter(final CodeAreaCore codeArea) {
|
||||
this.codeArea = codeArea;
|
||||
|
||||
colorAssessor = new DefaultCodeAreaColorAssessor();
|
||||
charAssessor = new DefaultCodeAreaCharAssessor();
|
||||
|
||||
scrollPanel = new DefaultCodeAreaScrollPane(codeArea.getContext()) {
|
||||
@Override
|
||||
protected void onScrollChanged(int horizontal, int vertical, int oldHorizontal, int oldVertical) {
|
||||
@@ -186,6 +190,7 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
paintMainArea(canvas);
|
||||
}
|
||||
};
|
||||
dataView.setContentDescription("Code area");
|
||||
dataView.setLongClickable(true);
|
||||
scrollPanel.addView(dataView);
|
||||
|
||||
@@ -606,6 +611,9 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
// Rect clipBounds = g.getClipBounds();
|
||||
// Rect mainArea = dimensions.getMainAreaRectangle();
|
||||
// g.clipRect(clipBounds != null ? CodeAreaAndroidUtils.computeIntersection(mainArea, clipBounds) : mainArea);
|
||||
colorAssessor.startPaint(this);
|
||||
charAssessor.startPaint(this);
|
||||
|
||||
paintBackground(g);
|
||||
|
||||
Rect dataViewRectangle = dimensions.getDataViewRectangle();
|
||||
@@ -764,28 +772,7 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
int skipRestFromPreview = visibility.getSkipRestFromPreview();
|
||||
int endPreview = Math.min(skipRestFromPreview, rowBytesLimit);
|
||||
for (int byteOnRow = skipToPreview; byteOnRow < endPreview; byteOnRow++) {
|
||||
byte dataByte = rowDataCache.rowData[byteOnRow];
|
||||
|
||||
if (maxBytesPerChar > 1) {
|
||||
if (dataPosition + maxBytesPerChar > dataSize) {
|
||||
maxBytesPerChar = (int) (dataSize - dataPosition);
|
||||
}
|
||||
|
||||
int charDataLength = maxBytesPerChar;
|
||||
if (byteOnRow + charDataLength > rowDataCache.rowData.length) {
|
||||
charDataLength = rowDataCache.rowData.length - byteOnRow;
|
||||
}
|
||||
String displayString = new String(rowDataCache.rowData, byteOnRow, charDataLength, charset);
|
||||
if (!displayString.isEmpty()) {
|
||||
rowDataCache.rowCharacters[previewCharPos + byteOnRow] = displayString.charAt(0);
|
||||
}
|
||||
} else {
|
||||
if (charMappingCharset == null || charMappingCharset != charset) {
|
||||
buildCharMapping(charset);
|
||||
}
|
||||
|
||||
rowDataCache.rowCharacters[previewCharPos + byteOnRow] = charMapping[dataByte & 0xFF];
|
||||
}
|
||||
rowDataCache.rowCharacters[previewCharPos + byteOnRow] = charAssessor.getPreviewCharacter(dataPosition, byteOnRow, previewCharPos, BasicCodeAreaSection.TEXT_PREVIEW);
|
||||
}
|
||||
if (bytesPerRow > rowBytesLimit) {
|
||||
Arrays.fill(rowDataCache.rowCharacters, previewCharPos + rowBytesLimit, previewCharPos + bytesPerRow, ' ');
|
||||
@@ -808,9 +795,9 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
int skipToChar = visibility.getSkipToChar();
|
||||
int skipRestFromChar = visibility.getSkipRestFromChar();
|
||||
int rowHeight = metrics.getRowHeight();
|
||||
int subFontSpace = metrics.getSubFontSpace();
|
||||
CodeAreaSelection selectionHandler = ((SelectionCapable) codeArea).getSelectionHandler();
|
||||
|
||||
int positionY = rowPositionY + rowHeight - subFontSpace;
|
||||
int positionY = rowPositionY + rowHeight;
|
||||
|
||||
int renderOffset = skipToChar;
|
||||
Integer renderColor = null;
|
||||
@@ -826,7 +813,8 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
}
|
||||
boolean sequenceBreak = false;
|
||||
|
||||
Integer color = getPositionBackgroundColor(rowDataPosition, byteOnRow, charOnRow, section);
|
||||
boolean inSelection = selectionHandler.isInSelection(rowDataPosition + byteOnRow);
|
||||
Integer color = colorAssessor.getPositionBackgroundColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
if (!CodeAreaAndroidUtils.areSameColors(color, renderColor)) {
|
||||
sequenceBreak = true;
|
||||
}
|
||||
@@ -855,33 +843,6 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns background color for particular code.
|
||||
*
|
||||
* @param rowDataPosition row data position
|
||||
* @param byteOnRow byte on current row
|
||||
* @param charOnRow character on current row
|
||||
* @param section current section
|
||||
* @return color or null for default color
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getPositionBackgroundColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section) {
|
||||
CodeAreaSelection selectionHandler = ((SelectionCapable) codeArea).getSelectionHandler();
|
||||
int codeLastCharPos = visibility.getCodeLastCharPos();
|
||||
boolean inSelection = selectionHandler.isInSelection(rowDataPosition + byteOnRow);
|
||||
if (inSelection && (section == BasicCodeAreaSection.CODE_MATRIX)) {
|
||||
if (charOnRow == codeLastCharPos) {
|
||||
inSelection = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (inSelection) {
|
||||
return section == ((CaretCapable) codeArea).getActiveSection() ? colorsProfile.getSelectionBackground() : colorsProfile.getSelectionMirrorBackground();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public PositionScrollVisibility computePositionScrollVisibility(CodeAreaCaretPosition caretPosition) {
|
||||
@@ -974,6 +935,7 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
int rowHeight = metrics.getRowHeight();
|
||||
int characterWidth = metrics.getCharacterWidth();
|
||||
int subFontSpace = metrics.getSubFontSpace();
|
||||
CodeAreaSelection selectionHandler = ((SelectionCapable) codeArea).getSelectionHandler();
|
||||
|
||||
int positionY = rowPositionY + rowHeight - subFontSpace;
|
||||
|
||||
@@ -994,7 +956,8 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
section = BasicCodeAreaSection.CODE_MATRIX;
|
||||
}
|
||||
|
||||
Integer color = getPositionTextColor(rowDataPosition, byteOnRow, charOnRow, section);
|
||||
boolean inSelection = selectionHandler.isInSelection(rowDataPosition + byteOnRow);
|
||||
Integer color = colorAssessor.getPositionTextColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
if (color == null) {
|
||||
color = colorsProfile.getTextColor();
|
||||
}
|
||||
@@ -1037,24 +1000,26 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns background color for particular code.
|
||||
*
|
||||
* @param rowDataPosition row data position
|
||||
* @param byteOnRow byte on current row
|
||||
* @param charOnRow character on current row
|
||||
* @param section current section
|
||||
* @return color or null for default color
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getPositionTextColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section) {
|
||||
CodeAreaSelection selectionHandler = ((SelectionCapable) codeArea).getSelectionHandler();
|
||||
boolean inSelection = selectionHandler.isInSelection(rowDataPosition + byteOnRow);
|
||||
if (inSelection) {
|
||||
return section == ((CaretCapable) codeArea).getActiveSection() ? colorsProfile.getSelectionColor() : colorsProfile.getSelectionMirrorColor();
|
||||
}
|
||||
@Nonnull
|
||||
@Override
|
||||
public CodeAreaColorAssessor getColorAssessor() {
|
||||
return colorAssessor;
|
||||
}
|
||||
|
||||
return null;
|
||||
@Override
|
||||
public void setColorAssessor(CodeAreaColorAssessor colorAssessor) {
|
||||
this.colorAssessor = CodeAreaUtils.requireNonNull(colorAssessor);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CodeAreaCharAssessor getCharAssessor() {
|
||||
return charAssessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharAssessor(CodeAreaCharAssessor charAssessor) {
|
||||
this.charAssessor = charAssessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1095,12 +1060,9 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
g.save();
|
||||
Rect clipBounds = g.getClipBounds();
|
||||
Rect mainAreaRect = dimensions.getMainAreaRectangle();
|
||||
mainAreaRect.left += dataViewOffsetX;
|
||||
mainAreaRect.right += dataViewOffsetX;
|
||||
mainAreaRect.bottom += dataViewOffsetY;
|
||||
mainAreaRect.top += dataViewOffsetY;
|
||||
Rect mainAreaRectAdj = new Rect(mainAreaRect.left + dataViewOffsetX, mainAreaRect.top + dataViewOffsetY, mainAreaRect.right + dataViewOffsetX, mainAreaRect.bottom + dataViewOffsetY);
|
||||
|
||||
Rect intersection = CodeAreaAndroidUtils.computeIntersection(mainAreaRect, scrolledCursorRect);
|
||||
Rect intersection = CodeAreaAndroidUtils.computeIntersection(mainAreaRectAdj, scrolledCursorRect);
|
||||
boolean cursorVisible = caret.isCursorVisible() && (intersection == null || !intersection.isEmpty());
|
||||
|
||||
if (cursorVisible) {
|
||||
@@ -1113,22 +1075,27 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
paintCursorRect(g, intersection, scrolledCursorRect, cursorRect, renderingMode, caret);
|
||||
}
|
||||
|
||||
// // Paint mirror cursor
|
||||
// if (viewMode == CodeAreaViewMode.DUAL && showMirrorCursor) {
|
||||
// Rect mirrorCursorRect = getMirrorCursorRect(caret.getDataPosition(), caret.getSection());
|
||||
// if (mirrorCursorRect != null) {
|
||||
// intersection = CodeAreaAndroidUtils.computeIntersection(mainAreaRect, mirrorCursorRect);
|
||||
// boolean mirrorCursorVisible = !intersection.isEmpty();
|
||||
// if (mirrorCursorVisible) {
|
||||
// g.clipRect(intersection);
|
||||
// paint.setColor(colorsProfile.getCursor();
|
||||
//// Graphics2D g2d = (Graphics2D) g.create();
|
||||
//// Stroke dashed = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{2}, 0);
|
||||
//// g2d.setStroke(dashed);
|
||||
// g.drawRect(mirrorCursorRect.left, mirrorCursorRect.top, mirrorCursorRect.right - 1, mirrorCursorRect.bottom - 1, paint);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// Paint mirror cursor
|
||||
if (viewMode == CodeAreaViewMode.DUAL && showMirrorCursor) {
|
||||
updateMirrorCursorRect(caret.getDataPosition(), caret.getSection());
|
||||
Rect mirrorCursorRect = cursorDataCache.mirrorCursorRect;
|
||||
if (mirrorCursorRect != null) {
|
||||
Rect mirrorCursorRectAdj = new Rect(mirrorCursorRect.left + dataViewOffsetX, mirrorCursorRect.top + dataViewOffsetY, mirrorCursorRect.right + dataViewOffsetX, mirrorCursorRect.bottom + dataViewOffsetY);
|
||||
intersection = CodeAreaAndroidUtils.computeIntersection(mainAreaRectAdj, mirrorCursorRectAdj);
|
||||
boolean mirrorCursorVisible = intersection != null && !intersection.isEmpty();
|
||||
if (mirrorCursorVisible) {
|
||||
g.restore();
|
||||
g.save();
|
||||
g.clipRect(intersection);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setColor(colorsProfile.getCursorColor());
|
||||
paint.setPathEffect(cursorDataCache.dashedStroke);
|
||||
g.drawRect(mirrorCursorRectAdj.left, mirrorCursorRectAdj.top, mirrorCursorRectAdj.right - 1, mirrorCursorRectAdj.bottom - 1, paint);
|
||||
paint.setPathEffect(null);
|
||||
paint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
}
|
||||
}
|
||||
}
|
||||
g.restore();
|
||||
}
|
||||
|
||||
@@ -1160,7 +1127,7 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
|
||||
g.drawRect(scrolledCursorRect, paint);
|
||||
paint.setColor(colorsProfile.getCursorNegativeColor());
|
||||
BinaryData codeAreaData = codeArea.getContentData();
|
||||
BinaryData contentData = codeArea.getContentData();
|
||||
int row = (cursorRect.top + scrollPosition.getRowOffset() - dataViewY) / rowHeight;
|
||||
int scrolledX = cursorRect.left + scrollPosition.getCharPosition() * characterWidth + scrollPosition.getCharOffset();
|
||||
int posY = dataViewY + (row + 1) * rowHeight - subFontSpace - scrollPosition.getRowOffset();
|
||||
@@ -1171,30 +1138,23 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
break;
|
||||
}
|
||||
|
||||
if (maxBytesPerChar > 1) {
|
||||
int charDataLength = maxBytesPerChar;
|
||||
if (dataPosition + maxBytesPerChar > dataSize) {
|
||||
charDataLength = (int) (dataSize - dataPosition);
|
||||
}
|
||||
int byteOnRow = (int) (dataPosition % structure.getBytesPerRow());
|
||||
int previewCharPos = visibility.getPreviewCharPos();
|
||||
|
||||
if (codeAreaData == null) {
|
||||
cursorDataCache.cursorChars[0] = ' ';
|
||||
} else {
|
||||
codeAreaData.copyToArray(dataPosition, cursorDataCache.cursorData, 0, charDataLength);
|
||||
String displayString = new String(cursorDataCache.cursorData, 0, charDataLength, charset);
|
||||
if (!displayString.isEmpty()) {
|
||||
cursorDataCache.cursorChars[0] = displayString.charAt(0);
|
||||
}
|
||||
}
|
||||
if (contentData.isEmpty()) {
|
||||
cursorDataCache.cursorChars[0] = charAssessor.getPreviewCursorCharacter(dataPosition, byteOnRow, previewCharPos, cursorDataCache.cursorData, 0, BasicCodeAreaSection.TEXT_PREVIEW);
|
||||
} else {
|
||||
if (charMappingCharset == null || charMappingCharset != charset) {
|
||||
buildCharMapping(charset);
|
||||
}
|
||||
if (maxBytesPerChar > 1) {
|
||||
int charDataLength = maxBytesPerChar;
|
||||
if (dataPosition + maxBytesPerChar > dataSize) {
|
||||
charDataLength = (int) (dataSize - dataPosition);
|
||||
}
|
||||
|
||||
if (codeAreaData == null) {
|
||||
cursorDataCache.cursorChars[0] = ' ';
|
||||
contentData.copyToArray(dataPosition, cursorDataCache.cursorData, 0, charDataLength);
|
||||
cursorDataCache.cursorChars[0] = charAssessor.getPreviewCursorCharacter(dataPosition, byteOnRow, previewCharPos, cursorDataCache.cursorData, charDataLength, BasicCodeAreaSection.TEXT_PREVIEW);
|
||||
} else {
|
||||
cursorDataCache.cursorChars[0] = charMapping[codeAreaData.getByte(dataPosition) & 0xFF];
|
||||
cursorDataCache.cursorData[0] = contentData.getByte(dataPosition);
|
||||
cursorDataCache.cursorChars[0] = charAssessor.getPreviewCursorCharacter(dataPosition, byteOnRow, previewCharPos, cursorDataCache.cursorData, 1, BasicCodeAreaSection.TEXT_PREVIEW);
|
||||
}
|
||||
}
|
||||
int posX = previewRelativeX + charPos * characterWidth - scrollPosition.getCharPosition() * characterWidth - scrollPosition.getCharOffset();
|
||||
@@ -1208,8 +1168,8 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
int byteOffset = structure.computePositionByte(charPos);
|
||||
int codeCharPos = structure.computeFirstCodeCharacterPos(byteOffset);
|
||||
|
||||
if (codeAreaData != null && dataPosition < dataSize) {
|
||||
byte dataByte = codeAreaData.getByte(dataPosition);
|
||||
if (dataPosition < dataSize) {
|
||||
byte dataByte = contentData.getByte(dataPosition);
|
||||
CodeAreaUtils.byteToCharsCode(dataByte, codeType, cursorDataCache.cursorChars, 0, codeCharactersCase);
|
||||
} else {
|
||||
Arrays.fill(cursorDataCache.cursorChars, ' ');
|
||||
@@ -1357,16 +1317,14 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
return new Point(caretX, caretY);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Rect getMirrorCursorRect(long dataPosition, CodeAreaSection section) {
|
||||
private void updateMirrorCursorRect(long dataPosition, CodeAreaSection section) {
|
||||
CodeType codeType = structure.getCodeType();
|
||||
Point mirrorCursorPoint = getPositionPoint(dataPosition, 0, section == BasicCodeAreaSection.CODE_MATRIX ? BasicCodeAreaSection.TEXT_PREVIEW : BasicCodeAreaSection.CODE_MATRIX);
|
||||
if (mirrorCursorPoint == null) {
|
||||
return null;
|
||||
cursorDataCache.mirrorCursorRect.setEmpty();
|
||||
} else {
|
||||
cursorDataCache.mirrorCursorRect = new Rect(mirrorCursorPoint.x, mirrorCursorPoint.y, mirrorCursorPoint.x + metrics.getCharacterWidth() * (section == BasicCodeAreaSection.TEXT_PREVIEW ? codeType.getMaxDigitsForByte() : 1), mirrorCursorPoint.y + metrics.getRowHeight());
|
||||
}
|
||||
|
||||
Rect mirrorCursorRect = new Rect(mirrorCursorPoint.x, mirrorCursorPoint.y, mirrorCursorPoint.x + metrics.getCharacterWidth() * (section == BasicCodeAreaSection.TEXT_PREVIEW ? codeType.getMaxDigitsForByte() : 1), mirrorCursorPoint.y + metrics.getRowHeight());
|
||||
return mirrorCursorRect;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1458,18 +1416,6 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
g.drawText(drawnChars, charOffset, length, positionX, positionY, paint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Precomputes widths for basic ascii characters.
|
||||
*
|
||||
* @param charset character set
|
||||
*/
|
||||
private void buildCharMapping(Charset charset) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
charMapping[i] = new String(new byte[]{(byte) i}, charset).charAt(0);
|
||||
}
|
||||
charMappingCharset = charset;
|
||||
}
|
||||
|
||||
private int getRowPositionLength() {
|
||||
if (minRowPositionLength > 0 && minRowPositionLength == maxRowPositionLength) {
|
||||
return minRowPositionLength;
|
||||
@@ -1628,10 +1574,67 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
recomputeLayout();
|
||||
}
|
||||
|
||||
protected int getCharactersPerRow() {
|
||||
@Override
|
||||
public int getCharactersPerRow() {
|
||||
return structure.getCharactersPerRow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytesPerRow() {
|
||||
return structure.getBytesPerRow();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CodeAreaSection getActiveSection() {
|
||||
return ((CaretCapable) codeArea).getActiveSection();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Charset getCharset() {
|
||||
return charset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxBytesPerChar() {
|
||||
return metrics.getMaxBytesPerChar();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CodeAreaColorsProfile getColorsProfile() {
|
||||
return colorsProfile;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public byte[] getRowData() {
|
||||
return rowDataCache.rowData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCodeLastCharPos() {
|
||||
return visibility.getCodeLastCharPos();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDataSize() {
|
||||
return structure.getDataSize();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public BinaryData getContentData() {
|
||||
return codeArea.getContentData();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CodeAreaSelection getSelectionHandler() {
|
||||
return ((SelectionCapable) codeArea).getSelectionHandler();
|
||||
}
|
||||
|
||||
private int getHorizontalScrollBarSize() {
|
||||
// JScrollBar horizontalScrollBar = scrollPanel.getHorizontalScrollBar();
|
||||
// int size;
|
||||
@@ -1668,9 +1671,9 @@ public class DefaultCodeAreaPainter implements CodeAreaPainter, BasicColorsCapab
|
||||
|
||||
private static class CursorDataCache {
|
||||
|
||||
Rectangle caretRect = new Rectangle();
|
||||
Rectangle mirrorCursorRect = new Rectangle();
|
||||
// final Stroke dashedStroke = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{2}, 0);
|
||||
Rect caretRect = new Rect();
|
||||
Rect mirrorCursorRect = new Rect();
|
||||
final DashPathEffect dashedStroke = new DashPathEffect(new float[] {4f, 4f}, 0f);
|
||||
int cursorCharsLength;
|
||||
char[] cursorChars;
|
||||
int cursorDataLength;
|
||||
|
||||
@@ -30,8 +30,8 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class DefaultCodeAreaScrollPane extends TwoDimensionScrollView {
|
||||
|
||||
private volatile boolean scrollingByUser = false;
|
||||
private volatile boolean scrollingUpdate = false;
|
||||
protected volatile boolean scrollingByUser = false;
|
||||
protected volatile boolean scrollingUpdate = false;
|
||||
|
||||
public DefaultCodeAreaScrollPane(Context context) {
|
||||
super(context);
|
||||
@@ -50,11 +50,15 @@ public class DefaultCodeAreaScrollPane extends TwoDimensionScrollView {
|
||||
|
||||
private void init() {
|
||||
setScrollContainer(true);
|
||||
// setHorizontalScrollBarEnabled(true);
|
||||
// setVerticalScrollBarEnabled(true);
|
||||
// setHorizontalFadingEdgeEnabled(false);
|
||||
}
|
||||
|
||||
public void updateScrollBars(int verticalScrollValue, int horizontalScrollValue) {
|
||||
scrollingUpdate = true;
|
||||
scrollTo(horizontalScrollValue, verticalScrollValue);
|
||||
// awakenScrollBars();
|
||||
scrollingUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
+13
-13
@@ -46,29 +46,29 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||
public class BasicCodeAreaColorsProfile implements CodeAreaColorsProfile {
|
||||
|
||||
@Nullable
|
||||
private Integer textColor;
|
||||
protected Integer textColor;
|
||||
@Nullable
|
||||
private Integer textBackground;
|
||||
protected Integer textBackground;
|
||||
@Nullable
|
||||
private Integer selectionColor;
|
||||
protected Integer selectionColor;
|
||||
@Nullable
|
||||
private Integer selectionBackground;
|
||||
protected Integer selectionBackground;
|
||||
@Nullable
|
||||
private Integer selectionMirrorColor;
|
||||
protected Integer selectionMirrorColor;
|
||||
@Nullable
|
||||
private Integer selectionMirrorBackground;
|
||||
protected Integer selectionMirrorBackground;
|
||||
@Nullable
|
||||
private Integer alternateColor;
|
||||
protected Integer alternateColor;
|
||||
@Nullable
|
||||
private Integer alternateBackground;
|
||||
protected Integer alternateBackground;
|
||||
@Nullable
|
||||
private Integer cursorColor;
|
||||
protected Integer cursorColor;
|
||||
@Nullable
|
||||
private Integer cursorNegativeColor;
|
||||
protected Integer cursorNegativeColor;
|
||||
@Nullable
|
||||
private Integer decorationLine;
|
||||
protected Integer decorationLine;
|
||||
@Nullable
|
||||
private Context context;
|
||||
protected Context context;
|
||||
|
||||
public BasicCodeAreaColorsProfile() {
|
||||
}
|
||||
@@ -174,7 +174,7 @@ public class BasicCodeAreaColorsProfile implements CodeAreaColorsProfile {
|
||||
if (textBackground == null) {
|
||||
textBackground = CodeAreaAndroidUtils.createNegativeColor(textColor);
|
||||
}
|
||||
selectionColor = getThemeColor(androidx.appcompat.R.attr.editTextColor);
|
||||
selectionColor = textColor; // getThemeColor(androidx.appcompat.R.attr.editTextColor);
|
||||
if (selectionColor == null) {
|
||||
selectionColor = isDarkMode() ? Color.BLACK : Color.WHITE;
|
||||
}
|
||||
|
||||
@@ -15,12 +15,10 @@
|
||||
*/
|
||||
package org.exbin.bined.android.capability;
|
||||
|
||||
import org.exbin.bined.android.basic.color.BasicCodeAreaColorsProfile;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.android.basic.color.BasicCodeAreaColorsProfile;
|
||||
|
||||
/**
|
||||
* Support for basic set of colors.
|
||||
@@ -30,8 +28,18 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface BasicColorsCapable {
|
||||
|
||||
/**
|
||||
* Returns basic profile for colors.
|
||||
*
|
||||
* @return colors profile
|
||||
*/
|
||||
@Nonnull
|
||||
Optional<BasicCodeAreaColorsProfile> getBasicColors();
|
||||
|
||||
void setBasicColors(BasicCodeAreaColorsProfile colors);
|
||||
/**
|
||||
* Sets basic profile for colors.
|
||||
*
|
||||
* @param colorsProfile colors profile
|
||||
*/
|
||||
void setBasicColors(BasicCodeAreaColorsProfile colorsProfile);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.android.capability;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.android.CodeAreaCharAssessor;
|
||||
|
||||
/**
|
||||
* Painter support for character assessor capability.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface CharAssessorPainterCapable {
|
||||
|
||||
/**
|
||||
* Returns character assessor.
|
||||
*
|
||||
* @return character assessor
|
||||
*/
|
||||
@Nonnull
|
||||
CodeAreaCharAssessor getCharAssessor();
|
||||
|
||||
/**
|
||||
* Sets character assessor.
|
||||
*
|
||||
* @param charAssessor character assessor
|
||||
*/
|
||||
void setCharAssessor(CodeAreaCharAssessor charAssessor);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.android.capability;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.android.CodeAreaColorAssessor;
|
||||
|
||||
/**
|
||||
* Painter support for color assessor capability.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface ColorAssessorPainterCapable {
|
||||
|
||||
/**
|
||||
* Returns color assessor.
|
||||
*
|
||||
* @return color assessor
|
||||
*/
|
||||
@Nonnull
|
||||
CodeAreaColorAssessor getColorAssessor();
|
||||
|
||||
/**
|
||||
* Sets color assessor.
|
||||
*
|
||||
* @param colorAssessor color assessor
|
||||
*/
|
||||
void setColorAssessor(CodeAreaColorAssessor colorAssessor);
|
||||
}
|
||||
@@ -28,8 +28,18 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface FontCapable {
|
||||
|
||||
/**
|
||||
* Returns font used for text painting.
|
||||
*
|
||||
* @return font
|
||||
*/
|
||||
@Nonnull
|
||||
Font getCodeFont();
|
||||
|
||||
void setCodeFont(Font font);
|
||||
/**
|
||||
* Sets font used for text painting.
|
||||
*
|
||||
* @param codeFont font
|
||||
*/
|
||||
void setCodeFont(Font codeFont);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,10 @@ package org.exbin.bined.editor.android;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -29,9 +32,22 @@ import androidx.fragment.app.FragmentActivity;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
/**
|
||||
* About application dialog.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class AboutDialog extends AppCompatDialogFragment {
|
||||
|
||||
private static final String DONATE_LINK = "https://bined.exbin.org/?p=donate";
|
||||
|
||||
private String appVersion;
|
||||
|
||||
public void setAppVersion(String appVersion) {
|
||||
this.appVersion = appVersion;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
@@ -44,11 +60,17 @@ public class AboutDialog extends AppCompatDialogFragment {
|
||||
// Pass null as the parent view because its going in the
|
||||
// dialog layout
|
||||
View aboutView = inflater.inflate(R.layout.about_view, null);
|
||||
TextView textView = (TextView) aboutView.findViewById(R.id.textView);
|
||||
TextView textView = aboutView.findViewById(R.id.textView);
|
||||
String htmlString = String.format(getResources().getString(R.string.app_about), appVersion).replace("\n", "<br/>");
|
||||
textView.setText(Html.fromHtml(htmlString, Html.FROM_HTML_MODE_COMPACT));
|
||||
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
builder.setView(aboutView);
|
||||
builder.setPositiveButton(getResources().getString(R.string.button_close), (dialog, which) -> {
|
||||
});
|
||||
builder.setNeutralButton(getResources().getString(R.string.button_donate), (dialog, which) -> {
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(DONATE_LINK));
|
||||
startActivity(browserIntent);
|
||||
});
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.editor.android;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import org.exbin.bined.editor.android.preference.BinaryEditorPreferences;
|
||||
import org.exbin.bined.editor.android.preference.PreferencesWrapper;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
/**
|
||||
* Application context.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class ApplicationContext extends Application {
|
||||
|
||||
private BinaryEditorPreferences appPreferences;
|
||||
|
||||
private BinEdFileHandler fileHandler = null;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
appPreferences = new BinaryEditorPreferences(new PreferencesWrapper(getApplicationContext()));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public BinaryEditorPreferences getAppPreferences() {
|
||||
return appPreferences;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BinEdFileHandler getFileHandler() {
|
||||
return fileHandler;
|
||||
}
|
||||
|
||||
public void setFileHandler(BinEdFileHandler fileHandler) {
|
||||
this.fileHandler = fileHandler;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.editor.android;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.exbin.auxiliary.binary_data.BinaryData;
|
||||
import org.exbin.auxiliary.binary_data.ByteArrayEditableData;
|
||||
import org.exbin.bined.EditOperation;
|
||||
import org.exbin.bined.android.CodeAreaPainter;
|
||||
import org.exbin.bined.android.basic.CodeArea;
|
||||
import org.exbin.bined.android.capability.CharAssessorPainterCapable;
|
||||
import org.exbin.bined.android.capability.ColorAssessorPainterCapable;
|
||||
import org.exbin.bined.operation.android.CodeAreaOperationCommandHandler;
|
||||
import org.exbin.bined.operation.android.CodeAreaUndoRedo;
|
||||
import org.exbin.framework.bined.BinEdCodeAreaAssessor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
/**
|
||||
* File handler for binary editor.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class BinEdFileHandler {
|
||||
|
||||
private CodeArea codeArea;
|
||||
private CodeAreaUndoRedo undoRedo;
|
||||
|
||||
private long documentOriginalSize = 0;
|
||||
private Uri currentFileUri = null;
|
||||
private Uri pickerInitialUri = null;
|
||||
|
||||
public BinEdFileHandler(CodeArea codeArea) {
|
||||
// ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
this.codeArea = codeArea;
|
||||
codeArea.setContentData(new ByteArrayEditableData());
|
||||
codeArea.setEditOperation(EditOperation.INSERT);
|
||||
undoRedo = new CodeAreaUndoRedo(codeArea);
|
||||
|
||||
CodeAreaOperationCommandHandler commandHandler = new CodeAreaOperationCommandHandler(codeArea.getContext(), codeArea, undoRedo);
|
||||
codeArea.setCommandHandler(commandHandler);
|
||||
CodeAreaPainter painter = codeArea.getPainter();
|
||||
BinEdCodeAreaAssessor codeAreaAssessor = new BinEdCodeAreaAssessor(((ColorAssessorPainterCapable) painter).getColorAssessor(), ((CharAssessorPainterCapable) painter).getCharAssessor());
|
||||
((ColorAssessorPainterCapable) painter).setColorAssessor(codeAreaAssessor);
|
||||
((CharAssessorPainterCapable) painter).setCharAssessor(codeAreaAssessor);
|
||||
codeArea.setPainter(painter);
|
||||
}
|
||||
|
||||
public void newFile() {
|
||||
codeArea.setContentData(new ByteArrayEditableData());
|
||||
undoRedo.clear();
|
||||
currentFileUri = null;
|
||||
|
||||
documentOriginalSize = 0;
|
||||
}
|
||||
|
||||
public void openFile(ContentResolver contentResolver, Uri fileUri) {
|
||||
ByteArrayEditableData fileData = new ByteArrayEditableData();
|
||||
try {
|
||||
InputStream inputStream = contentResolver.openInputStream(fileUri);
|
||||
if (inputStream == null) {
|
||||
return;
|
||||
}
|
||||
fileData.loadFromStream(inputStream);
|
||||
inputStream.close();
|
||||
documentOriginalSize = fileData.getDataSize();
|
||||
undoRedo.clear();
|
||||
codeArea.setContentData(fileData);
|
||||
currentFileUri = fileUri;
|
||||
pickerInitialUri = fileUri;
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(BinEdFileHandler.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveFile(ContentResolver contentResolver, Uri fileUri) {
|
||||
BinaryData contentData = codeArea.getContentData();
|
||||
try {
|
||||
OutputStream outputStream = contentResolver.openOutputStream(fileUri);
|
||||
if (outputStream == null) {
|
||||
return;
|
||||
}
|
||||
codeArea.getContentData().saveToStream(outputStream);
|
||||
outputStream.close();
|
||||
documentOriginalSize = contentData.getDataSize();
|
||||
undoRedo.setSyncPosition();
|
||||
currentFileUri = fileUri;
|
||||
pickerInitialUri = fileUri;
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(BinEdFileHandler.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public CodeArea getCodeArea() {
|
||||
return codeArea;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public CodeAreaUndoRedo getUndoRedo() {
|
||||
return undoRedo;
|
||||
}
|
||||
|
||||
public long getDocumentOriginalSize() {
|
||||
return documentOriginalSize;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Uri getCurrentFileUri() {
|
||||
return currentFileUri;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Uri getPickerInitialUri() {
|
||||
return pickerInitialUri;
|
||||
}
|
||||
|
||||
public void clearFileUri() {
|
||||
currentFileUri = null;
|
||||
pickerInitialUri = null;
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
return undoRedo.isModified();
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,12 @@
|
||||
*/
|
||||
package org.exbin.bined.editor.android;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@@ -31,6 +35,7 @@ import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
@@ -43,46 +48,54 @@ import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.os.LocaleListCompat;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import com.rustamg.filedialogs.FileDialog;
|
||||
import com.rustamg.filedialogs.OpenFileDialog;
|
||||
import com.rustamg.filedialogs.SaveFileDialog;
|
||||
|
||||
import org.exbin.auxiliary.binary_data.BinaryData;
|
||||
import org.exbin.auxiliary.binary_data.ByteArrayEditableData;
|
||||
import org.exbin.bined.CaretOverlapMode;
|
||||
import org.exbin.bined.CodeAreaCaretListener;
|
||||
import org.exbin.bined.CodeAreaCaretPosition;
|
||||
import org.exbin.bined.CodeCharactersCase;
|
||||
import org.exbin.bined.CodeType;
|
||||
import org.exbin.bined.DataChangedListener;
|
||||
import org.exbin.bined.DefaultCodeAreaCaretPosition;
|
||||
import org.exbin.bined.EditMode;
|
||||
import org.exbin.bined.EditOperation;
|
||||
import org.exbin.bined.EditModeChangedListener;
|
||||
import org.exbin.bined.RowWrappingMode;
|
||||
import org.exbin.bined.SelectionChangedListener;
|
||||
import org.exbin.bined.SelectionRange;
|
||||
import org.exbin.bined.android.CodeAreaAndroidUtils;
|
||||
import org.exbin.bined.android.Font;
|
||||
import org.exbin.bined.android.basic.CodeArea;
|
||||
import org.exbin.bined.android.basic.color.BasicCodeAreaColorsProfile;
|
||||
import org.exbin.bined.android.capability.ColorAssessorPainterCapable;
|
||||
import org.exbin.bined.basic.BasicCodeAreaSection;
|
||||
import org.exbin.bined.basic.CodeAreaScrollPosition;
|
||||
import org.exbin.bined.basic.CodeAreaViewMode;
|
||||
import org.exbin.bined.capability.EditModeCapable;
|
||||
import org.exbin.bined.editor.android.options.Theme;
|
||||
import org.exbin.bined.editor.android.preference.BinaryEditorPreferences;
|
||||
import org.exbin.bined.editor.android.preference.EncodingPreference;
|
||||
import org.exbin.bined.editor.android.preference.FontPreference;
|
||||
import org.exbin.bined.editor.android.preference.MainPreferences;
|
||||
import org.exbin.bined.editor.android.preference.PreferencesWrapper;
|
||||
import org.exbin.bined.editor.android.search.BinarySearchService;
|
||||
import org.exbin.bined.editor.android.search.BinarySearchServiceImpl;
|
||||
import org.exbin.bined.editor.android.search.SearchCondition;
|
||||
import org.exbin.bined.editor.android.search.SearchParameters;
|
||||
import org.exbin.bined.highlight.android.HighlightNonAsciiCodeAreaPainter;
|
||||
import org.exbin.bined.operation.android.CodeAreaOperationCommandHandler;
|
||||
import org.exbin.bined.operation.android.CodeAreaUndoRedo;
|
||||
import org.exbin.bined.highlight.android.NonAsciiCodeAreaColorAssessor;
|
||||
import org.exbin.bined.highlight.android.NonprintablesCodeAreaAssessor;
|
||||
import org.exbin.bined.operation.undo.BinaryDataUndoRedoChangeListener;
|
||||
import org.exbin.framework.bined.BinaryStatusApi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -90,8 +103,13 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
/**
|
||||
* Main activity.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
public class MainActivity extends AppCompatActivity implements FileDialog.OnFileSelectedListener {
|
||||
|
||||
private static final int SELECTION_START_POPUP_ID = 1;
|
||||
private static final int SELECTION_END_POPUP_ID = 2;
|
||||
@@ -104,27 +122,20 @@ public class MainActivity extends AppCompatActivity {
|
||||
private static final int COPY_AS_CODE_ACTION_POPUP_ID = 9;
|
||||
private static final int PASTE_FROM_CODE_ACTION_POPUP_ID = 10;
|
||||
|
||||
private static final String CURSOR_POSITION_TAG = "bined.cursorPosition";
|
||||
private static final String CURSOR_OFFSET_TAG = "bined.cursorOffset";
|
||||
private static final String CURSOR_SECTION_TAG = "bined.cursorSection";
|
||||
private static final String SCROLL_ROW_POSITION_TAG = "bined.scrollRowPosition";
|
||||
private static final String SCROLL_ROW_OFFSET_TAG = "bined.scrollRowOffset";
|
||||
private static final String SCROLL_CHAR_POSITION_TAG = "bined.scrollCharPosition";
|
||||
private static final String SCROLL_CHAR_OFFSET_TAG = "bined.scrollOffsetPosition";
|
||||
private static final String SELECTION_START_TAG = "bined.selectionStart";
|
||||
private static final String SELECTION_END_TAG = "bined.selectionEnd";
|
||||
private static final int STORAGE_PERMISSION_CODE = 1;
|
||||
|
||||
private BinEdFileHandler fileHandler;
|
||||
private CodeArea codeArea;
|
||||
private CodeAreaUndoRedo undoRedo;
|
||||
private BinaryEditorPreferences appPreferences;
|
||||
|
||||
private long documentOriginalSize = 0;
|
||||
private Toolbar toolbar;
|
||||
private Menu menu;
|
||||
private static ByteArrayEditableData fileData = null;
|
||||
private Uri currentFileUri = null;
|
||||
private Uri pickerInitialUri = null;
|
||||
private SearchView searchView;
|
||||
private final BinaryStatusHandler binaryStatus = new BinaryStatusHandler(this);
|
||||
private BinarySearchService searchService;
|
||||
private Runnable postSaveAsAction = null;
|
||||
private boolean keyboardShown = false;
|
||||
|
||||
private final BinarySearchService.SearchStatusListener searchStatusListener = new BinarySearchService.SearchStatusListener() {
|
||||
@Override
|
||||
public void setStatus(BinarySearchService.FoundMatches foundMatches, SearchParameters.MatchMode matchMode) {
|
||||
@@ -136,9 +147,90 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
}
|
||||
};
|
||||
private final BinaryDataUndoRedoChangeListener codeAreaChangeListener = () -> {
|
||||
if (menu != null) {
|
||||
updateUndoState();
|
||||
}
|
||||
};
|
||||
private final DataChangedListener codeAreaDataChangedListener = () -> {
|
||||
// activeFile.getComponent().notifyDataChanged();
|
||||
// if (editorModificationListener != null) {
|
||||
// editorModificationListener.modified();
|
||||
// }
|
||||
updateCurrentDocumentSize();
|
||||
};
|
||||
private final SelectionChangedListener codeAreaSelectionChangedListener = () -> {
|
||||
binaryStatus.setSelectionRange(codeArea.getSelection());
|
||||
// updateClipboardActionsStatus();
|
||||
};
|
||||
private final CodeAreaCaretListener codeAreaCodeAreaCaretListener = caretPosition -> {
|
||||
binaryStatus.setCursorPosition(caretPosition);
|
||||
|
||||
private boolean keyboardShown = false;
|
||||
private BinaryEditorPreferences appPreferences;
|
||||
boolean showKeyboard = codeArea.getActiveSection() == BasicCodeAreaSection.TEXT_PREVIEW;
|
||||
if (showKeyboard != keyboardShown) {
|
||||
|
||||
keyboardShown = showKeyboard;
|
||||
InputMethodManager im = (InputMethodManager) codeArea.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
codeArea.requestFocus();
|
||||
if (showKeyboard) {
|
||||
im.showSoftInput(codeArea, InputMethodManager.SHOW_IMPLICIT);
|
||||
} else {
|
||||
im.hideSoftInputFromWindow(codeArea.getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
private final View.OnKeyListener codeAreaOnKeyListener = new View.OnKeyListener() {
|
||||
|
||||
private final KeyListener keyListener = new TextKeyListener(TextKeyListener.Capitalize.NONE, false);
|
||||
private final Editable editable = Editable.Factory.getInstance().newEditable("");
|
||||
|
||||
@Override
|
||||
public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
|
||||
try {
|
||||
if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DEL || keyEvent.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL) {
|
||||
editable.clear();
|
||||
codeArea.getCommandHandler().keyPressed(keyEvent);
|
||||
} else {
|
||||
keyListener.onKeyDown(view, editable, keyCode, keyEvent);
|
||||
processKeys(keyEvent);
|
||||
}
|
||||
} else if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
|
||||
editable.clear();
|
||||
if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) {
|
||||
if (keyEvent.getEventTime() - keyEvent.getDownTime() > TimeUnit.SECONDS.toMillis(1)) {
|
||||
codeArea.showContextMenu();
|
||||
} else {
|
||||
View keyStripeView = findViewById(R.id.controlPanel);
|
||||
keyStripeView.requestFocus();
|
||||
}
|
||||
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK && isGoogleTV(codeArea.getContext())) {
|
||||
toolbar.showOverflowMenu();
|
||||
} else {
|
||||
codeArea.getCommandHandler().keyPressed(keyEvent);
|
||||
}
|
||||
} else {
|
||||
keyListener.onKeyOther(view, editable, keyEvent);
|
||||
processKeys(keyEvent);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
// ignore
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void processKeys(KeyEvent keyEvent) {
|
||||
int outputCharsLength = editable.length();
|
||||
if (outputCharsLength > 0) {
|
||||
for (int i = 0; i < outputCharsLength; i++) {
|
||||
codeArea.getCommandHandler().keyTyped(editable.charAt(i), keyEvent);
|
||||
}
|
||||
editable.clear();
|
||||
}
|
||||
}
|
||||
};
|
||||
private final EditModeChangedListener codeAreaEditModeChangedListener = binaryStatus::setEditMode;
|
||||
|
||||
private final ActivityResultLauncher<Intent> openFileLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), this::openFileResultCallback);
|
||||
private final ActivityResultLauncher<Intent> saveFileLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), this::saveFileResultCallback);
|
||||
@@ -147,131 +239,106 @@ public class MainActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
appPreferences = new BinaryEditorPreferences(new PreferencesWrapper(getApplicationContext()));
|
||||
|
||||
ApplicationContext application = (ApplicationContext) getApplication();
|
||||
appPreferences = application.getAppPreferences();
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
MainPreferences mainPreferences = appPreferences.getMainPreferences();
|
||||
String theme = mainPreferences.getTheme();
|
||||
if ("dark".equals(theme)) {
|
||||
if (Theme.DARK.name().equalsIgnoreCase(theme)) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
} else if ("light".equals(theme)) {
|
||||
} else if (Theme.LIGHT.name().equalsIgnoreCase(theme)) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
|
||||
}
|
||||
|
||||
toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
// For now steal code area and keep it in application context
|
||||
fileHandler = application.getFileHandler();
|
||||
if (fileHandler == null) {
|
||||
codeArea = findViewById(R.id.codeArea);
|
||||
fileHandler = new BinEdFileHandler(codeArea);
|
||||
application.setFileHandler(fileHandler);
|
||||
} else {
|
||||
codeArea = fileHandler.getCodeArea();
|
||||
ViewGroup parentView = (ViewGroup) codeArea.getParent();
|
||||
parentView.removeView(codeArea);
|
||||
ViewGroup contentView = findViewById(R.id.contentMain);
|
||||
contentView.removeView(findViewById(R.id.codeArea));
|
||||
contentView.addView(codeArea);
|
||||
}
|
||||
|
||||
AppCompatDelegate.setApplicationLocales(LocaleListCompat.wrap(getLanguageLocaleList()));
|
||||
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
codeArea = findViewById(R.id.codeArea);
|
||||
codeArea.setEditOperation(EditOperation.INSERT);
|
||||
searchService = new BinarySearchServiceImpl(codeArea);
|
||||
|
||||
undoRedo = new CodeAreaUndoRedo(codeArea);
|
||||
undoRedo.addChangeListener(() -> {
|
||||
if (menu != null) {
|
||||
updateUndoState();
|
||||
}
|
||||
});
|
||||
|
||||
CodeAreaOperationCommandHandler commandHandler = new CodeAreaOperationCommandHandler(codeArea.getContext(), codeArea, undoRedo);
|
||||
codeArea.setCommandHandler(commandHandler);
|
||||
HighlightNonAsciiCodeAreaPainter painter = new HighlightNonAsciiCodeAreaPainter(codeArea);
|
||||
codeArea.setPainter(painter);
|
||||
BasicCodeAreaColorsProfile basicColors = painter.getBasicColors();
|
||||
BasicCodeAreaColorsProfile basicColors = codeArea.getBasicColors().orElse(null);
|
||||
if (basicColors == null) {
|
||||
throw new IllegalStateException("Missing colors profile");
|
||||
}
|
||||
basicColors.setContext(this);
|
||||
basicColors.reinitialize();
|
||||
painter.resetColors();
|
||||
codeArea.resetColors();
|
||||
|
||||
searchService = new BinarySearchServiceImpl(codeArea);
|
||||
|
||||
registerForContextMenu(codeArea);
|
||||
|
||||
if (fileData != null) {
|
||||
codeArea.setContentData(fileData);
|
||||
} else {
|
||||
codeArea.setContentData(new ByteArrayEditableData());
|
||||
}
|
||||
|
||||
codeArea.addDataChangedListener(() -> {
|
||||
// activeFile.getComponent().notifyDataChanged();
|
||||
// if (editorModificationListener != null) {
|
||||
// editorModificationListener.modified();
|
||||
// }
|
||||
updateCurrentDocumentSize();
|
||||
});
|
||||
|
||||
codeArea.addSelectionChangedListener(() -> {
|
||||
binaryStatus.setSelectionRange(codeArea.getSelection());
|
||||
// updateClipboardActionsStatus();
|
||||
});
|
||||
|
||||
codeArea.addCaretMovedListener((CodeAreaCaretPosition caretPosition) -> {
|
||||
binaryStatus.setCursorPosition(caretPosition);
|
||||
|
||||
boolean showKeyboard = codeArea.getActiveSection() == BasicCodeAreaSection.TEXT_PREVIEW;
|
||||
if (showKeyboard != keyboardShown) {
|
||||
|
||||
keyboardShown = showKeyboard;
|
||||
InputMethodManager im = (InputMethodManager)codeArea.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
codeArea.requestFocus();
|
||||
if (showKeyboard) {
|
||||
im.showSoftInput(codeArea, InputMethodManager.SHOW_IMPLICIT);
|
||||
} else {
|
||||
im.hideSoftInputFromWindow(codeArea.getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
codeArea.setOnKeyListener(new View.OnKeyListener() {
|
||||
|
||||
private final KeyListener keyListener = new TextKeyListener(TextKeyListener.Capitalize.NONE, false);
|
||||
private final Editable editable = Editable.Factory.getInstance().newEditable("");
|
||||
|
||||
@Override
|
||||
public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
|
||||
try {
|
||||
if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DEL || keyEvent.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL) {
|
||||
commandHandler.keyPressed(keyEvent);
|
||||
} else {
|
||||
keyListener.onKeyDown(view, editable, keyCode, keyEvent);
|
||||
processKeys(keyEvent);
|
||||
}
|
||||
} else if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
|
||||
commandHandler.keyPressed(keyEvent);
|
||||
} else {
|
||||
keyListener.onKeyOther(view, editable, keyEvent);
|
||||
processKeys(keyEvent);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
// ignore
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void processKeys(KeyEvent keyEvent) {
|
||||
int outputCharsLength = editable.length();
|
||||
if (outputCharsLength > 0) {
|
||||
for (int i = 0; i < outputCharsLength; i++) {
|
||||
commandHandler.keyTyped(editable.charAt(i), keyEvent);
|
||||
}
|
||||
editable.clear();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
codeArea.addEditModeChangedListener(binaryStatus::setEditMode);
|
||||
fileHandler.getUndoRedo().addChangeListener(codeAreaChangeListener);
|
||||
codeArea.addDataChangedListener(codeAreaDataChangedListener);
|
||||
codeArea.addSelectionChangedListener(codeAreaSelectionChangedListener);
|
||||
codeArea.addCaretMovedListener(codeAreaCodeAreaCaretListener);
|
||||
codeArea.addEditModeChangedListener(codeAreaEditModeChangedListener);
|
||||
codeArea.setOnKeyListener(codeAreaOnKeyListener);
|
||||
|
||||
applySettings();
|
||||
|
||||
processIntent(getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
codeArea.setOnKeyListener(null);
|
||||
codeArea.removeEditModeChangedListener(codeAreaEditModeChangedListener);
|
||||
codeArea.removeCaretMovedListener(codeAreaCodeAreaCaretListener);
|
||||
codeArea.removeSelectionChangedListener(codeAreaSelectionChangedListener);
|
||||
codeArea.removeDataChangedListener(codeAreaDataChangedListener);
|
||||
fileHandler.getUndoRedo().removeChangeListener(codeAreaChangeListener);
|
||||
}
|
||||
|
||||
private void processIntent(Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (action == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Intent.ACTION_VIEW.equals(action) || Intent.ACTION_EDIT.equals(action)) {
|
||||
String scheme = intent.getScheme();
|
||||
if ("file".equals(scheme) || "content".equals(scheme)) {
|
||||
Uri fileUri = intent.getData();
|
||||
if (fileUri != null) {
|
||||
releaseFile(() -> {
|
||||
fileHandler.openFile(getContentResolver(), fileUri);
|
||||
// Content should be opened as unspecified file
|
||||
if ("content".equals(scheme)) {
|
||||
fileHandler.clearFileUri();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private LocaleList getLanguageLocaleList() {
|
||||
String language = appPreferences.getMainPreferences().getLocaleTag();
|
||||
|
||||
if (language.isEmpty()) {
|
||||
return LocaleList.getEmptyLocaleList();
|
||||
} else if ("en".equals(language)) {
|
||||
return LocaleList.getDefault();
|
||||
return LocaleList.forLanguageTags("en_US");
|
||||
}
|
||||
|
||||
return LocaleList.forLanguageTags(language);
|
||||
@@ -318,15 +385,22 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
this.menu = menu;
|
||||
updateUndoState();
|
||||
|
||||
// Currently on Google TV access to app bar icons doesn't seem to work
|
||||
if (isGoogleTV(this)) {
|
||||
for (int i = 0; i < menu.size(); i++) {
|
||||
MenuItem menuItem = menu.getItem(i);
|
||||
menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
|
||||
}
|
||||
}
|
||||
|
||||
codeArea.addSelectionChangedListener(this::updateEditActionsState);
|
||||
updateUndoState();
|
||||
updateEditActionsState();
|
||||
|
||||
updateViewActionsState();
|
||||
|
||||
MenuItem searchMenuItem = menu.findItem(R.id.action_search);
|
||||
SearchView searchView = Objects.requireNonNull((SearchView) searchMenuItem.getActionView());
|
||||
searchView = Objects.requireNonNull((SearchView) searchMenuItem.getActionView());
|
||||
searchView.setSubmitButtonEnabled(true);
|
||||
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
@@ -441,37 +515,20 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
if (id == R.id.action_new) {
|
||||
releaseFile(() -> {
|
||||
codeArea.setContentData(new ByteArrayEditableData());
|
||||
undoRedo.clear();
|
||||
currentFileUri = null;
|
||||
|
||||
documentOriginalSize = 0;
|
||||
fileHandler.newFile();
|
||||
});
|
||||
|
||||
return true;
|
||||
} else if (id == R.id.action_open) {
|
||||
releaseFile(() -> {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("*/*");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
intent.putExtra(Intent.EXTRA_LOCALE_LIST, getLanguageLocaleList());
|
||||
}
|
||||
|
||||
if (pickerInitialUri != null) {
|
||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
|
||||
}
|
||||
|
||||
// startActivityForResult(intent, 1);
|
||||
openFileLauncher.launch(Intent.createChooser(intent, getResources().getString(R.string.select_file)));
|
||||
});
|
||||
releaseFile(this::openFile);
|
||||
|
||||
return true;
|
||||
} else if (id == R.id.action_save) {
|
||||
Uri currentFileUri = fileHandler.getCurrentFileUri();
|
||||
if (currentFileUri == null) {
|
||||
saveAs();
|
||||
} else {
|
||||
saveFile(currentFileUri);
|
||||
fileHandler.saveFile(getContentResolver(), currentFileUri);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -486,7 +543,17 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
return true;
|
||||
} else if (id == R.id.action_about) {
|
||||
PackageManager manager = this.getPackageManager();
|
||||
String appVersion = "";
|
||||
try {
|
||||
PackageInfo info = manager.getPackageInfo(this.getPackageName(), PackageManager.GET_ACTIVITIES);
|
||||
appVersion = info.versionName;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
AboutDialog aboutDialog = new AboutDialog();
|
||||
aboutDialog.setAppVersion(appVersion);
|
||||
aboutDialog.show(getSupportFragmentManager(), "aboutDialog");
|
||||
|
||||
return true;
|
||||
@@ -584,17 +651,32 @@ public class MainActivity extends AppCompatActivity {
|
||||
appPreferences.getCodeAreaPreferences().setMaxBytesPerRow(codeArea.getMaxBytesPerRow());
|
||||
menu.findItem(R.id.bytes_per_row_16).setChecked(true);
|
||||
return true;
|
||||
} else if (id == R.id.non_printable_characters) {
|
||||
boolean checked = item.isChecked();
|
||||
item.setChecked(!checked);
|
||||
NonprintablesCodeAreaAssessor nonprintablesCodeAreaAssessor = CodeAreaAndroidUtils.findColorAssessor((ColorAssessorPainterCapable) codeArea.getPainter(), NonprintablesCodeAreaAssessor.class);
|
||||
if (nonprintablesCodeAreaAssessor != null) {
|
||||
nonprintablesCodeAreaAssessor.setShowNonprintables(!checked);
|
||||
}
|
||||
appPreferences.getCodeAreaPreferences().setShowNonprintables(!checked);
|
||||
return true;
|
||||
} else if (id == R.id.code_colorization) {
|
||||
boolean checked = item.isChecked();
|
||||
item.setChecked(!checked);
|
||||
((HighlightNonAsciiCodeAreaPainter) codeArea.getPainter()).setNonAsciiHighlightingEnabled(!checked);
|
||||
NonAsciiCodeAreaColorAssessor nonAsciiColorAssessor = CodeAreaAndroidUtils.findColorAssessor((ColorAssessorPainterCapable) codeArea.getPainter(), NonAsciiCodeAreaColorAssessor.class);
|
||||
if (nonAsciiColorAssessor != null) {
|
||||
nonAsciiColorAssessor.setNonAsciiHighlightingEnabled(!checked);
|
||||
}
|
||||
appPreferences.getCodeAreaPreferences().setCodeColorization(!checked);
|
||||
return true;
|
||||
} else if (id == R.id.action_undo) {
|
||||
undoRedo.performUndo();
|
||||
fileHandler.getUndoRedo().performUndo();
|
||||
// TODO fix operations instead of validating
|
||||
codeArea.validateCaret();
|
||||
return true;
|
||||
} else if (id == R.id.action_redo) {
|
||||
undoRedo.performRedo();
|
||||
fileHandler.getUndoRedo().performRedo();
|
||||
codeArea.validateCaret();
|
||||
return true;
|
||||
} else if (id == R.id.action_cut) {
|
||||
codeArea.cut();
|
||||
@@ -604,6 +686,19 @@ public class MainActivity extends AppCompatActivity {
|
||||
return true;
|
||||
} else if (id == R.id.action_paste) {
|
||||
codeArea.paste();
|
||||
return true;
|
||||
} else if (id == R.id.action_search) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.action_search);
|
||||
searchView.setIconifiedByDefault(false);
|
||||
builder.setNegativeButton(R.string.button_cancel, (dialog, which) -> {
|
||||
searchService.clearMatches();
|
||||
});
|
||||
builder.setView(searchView);
|
||||
AlertDialog alertDialog = builder.create();
|
||||
alertDialog.show();
|
||||
searchView.requestFocus();
|
||||
|
||||
return true;
|
||||
} else if (id == R.id.action_delete) {
|
||||
codeArea.delete();
|
||||
@@ -622,8 +717,10 @@ public class MainActivity extends AppCompatActivity {
|
||||
DefaultCodeAreaCaretPosition caretPosition = new DefaultCodeAreaCaretPosition();
|
||||
caretPosition.setCodeOffset(0);
|
||||
caretPosition.setPosition(codeArea.getActiveCaretPosition());
|
||||
caretPosition.setDataPosition(Long.parseLong(inputNumber.getText().toString()));
|
||||
long targetPosition = Long.parseLong(inputNumber.getText().toString());
|
||||
caretPosition.setDataPosition(Math.min(targetPosition, codeArea.getDataSize()));
|
||||
codeArea.setActiveCaretPosition(caretPosition);
|
||||
codeArea.validateCaret();
|
||||
codeArea.centerOnCursor();
|
||||
});
|
||||
builder.setNegativeButton(R.string.button_cancel, null);
|
||||
@@ -637,7 +734,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
public void releaseFile(Runnable postReleaseAction) {
|
||||
if (!undoRedo.isModified()) {
|
||||
if (!fileHandler.isModified()) {
|
||||
postReleaseAction.run();
|
||||
return;
|
||||
}
|
||||
@@ -645,10 +742,11 @@ public class MainActivity extends AppCompatActivity {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.file_modified);
|
||||
builder.setPositiveButton(R.string.button_save, (dialog, which) -> {
|
||||
Uri currentFileUri = fileHandler.getCurrentFileUri();
|
||||
if (currentFileUri == null) {
|
||||
saveAs();
|
||||
} else {
|
||||
saveFile(currentFileUri);
|
||||
fileHandler.saveFile(getContentResolver(), currentFileUri);
|
||||
}
|
||||
postReleaseAction.run();
|
||||
});
|
||||
@@ -660,6 +758,61 @@ public class MainActivity extends AppCompatActivity {
|
||||
alertDialog.show();
|
||||
}
|
||||
|
||||
public void openFile() {
|
||||
if (MainActivity.isGoogleTV(this)) {
|
||||
fallBackOpenFile();
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("*/*");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
intent.putExtra(Intent.EXTRA_LOCALE_LIST, getLanguageLocaleList());
|
||||
}
|
||||
|
||||
Uri pickerInitialUri = fileHandler.getPickerInitialUri();
|
||||
if (pickerInitialUri != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
|
||||
}
|
||||
|
||||
try {
|
||||
openFileLauncher.launch(Intent.createChooser(intent, getResources().getString(R.string.select_file)));
|
||||
} catch (ActivityNotFoundException ex) {
|
||||
fallBackOpenFile();
|
||||
}
|
||||
}
|
||||
|
||||
private void fallBackOpenFile() {
|
||||
boolean permissionGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
|
||||
if (!permissionGranted) {
|
||||
requestWriteExternalStoragePermission();
|
||||
return;
|
||||
}
|
||||
|
||||
OpenFileDialog dialog = new OpenFileDialog();
|
||||
dialog.setStyle(DialogFragment.STYLE_NO_TITLE, R.style.AppTheme);
|
||||
dialog.show(getSupportFragmentManager(), OpenFileDialog.class.getName());
|
||||
}
|
||||
|
||||
private void requestWriteExternalStoragePermission() {
|
||||
final String[] permissions = new String[]{
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
, Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
};
|
||||
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setMessage(R.string.storage_permission_request);
|
||||
builder.setPositiveButton(R.string.button_request, (dialog, which) -> {
|
||||
ActivityCompat.requestPermissions(MainActivity.this, permissions, STORAGE_PERMISSION_CODE);
|
||||
});
|
||||
builder.setNegativeButton(R.string.button_cancel, null);
|
||||
builder.show();
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(MainActivity.this, permissions, STORAGE_PERMISSION_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveAs() {
|
||||
saveAs(null);
|
||||
}
|
||||
@@ -667,6 +820,11 @@ public class MainActivity extends AppCompatActivity {
|
||||
public void saveAs(@Nullable Runnable postSaveAsAction) {
|
||||
this.postSaveAsAction = postSaveAsAction;
|
||||
|
||||
if (MainActivity.isGoogleTV(this)) {
|
||||
fallBackSaveAs();
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("*/*");
|
||||
@@ -674,92 +832,43 @@ public class MainActivity extends AppCompatActivity {
|
||||
intent.putExtra(Intent.EXTRA_LOCALE_LIST, getLanguageLocaleList());
|
||||
}
|
||||
|
||||
if (pickerInitialUri != null) {
|
||||
Uri pickerInitialUri = fileHandler.getPickerInitialUri();
|
||||
if (pickerInitialUri != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);
|
||||
}
|
||||
|
||||
saveFileLauncher.launch(Intent.createChooser(intent, getResources().getString(R.string.save_as_file)));
|
||||
}
|
||||
|
||||
public void openFile(Uri fileUri) {
|
||||
fileData = new ByteArrayEditableData();
|
||||
try {
|
||||
InputStream inputStream = getContentResolver().openInputStream(fileUri);
|
||||
if (inputStream == null) {
|
||||
return;
|
||||
}
|
||||
fileData.loadFromStream(inputStream);
|
||||
inputStream.close();
|
||||
documentOriginalSize = fileData.getDataSize();
|
||||
undoRedo.clear();
|
||||
codeArea.setContentData(fileData);
|
||||
currentFileUri = fileUri;
|
||||
pickerInitialUri = fileUri;
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MainActivity.class.getName()).log(Level.SEVERE, null, ex);
|
||||
saveFileLauncher.launch(Intent.createChooser(intent, getResources().getString(R.string.save_as_file)));
|
||||
} catch (ActivityNotFoundException ex) {
|
||||
fallBackSaveAs();
|
||||
}
|
||||
}
|
||||
|
||||
public void saveFile(Uri fileUri) {
|
||||
BinaryData contentData = codeArea.getContentData();
|
||||
try {
|
||||
OutputStream outputStream = getContentResolver().openOutputStream(fileUri);
|
||||
if (outputStream == null) {
|
||||
return;
|
||||
}
|
||||
fileData.saveToStream(outputStream);
|
||||
outputStream.close();
|
||||
documentOriginalSize = contentData.getDataSize();
|
||||
undoRedo.setSyncPosition();
|
||||
currentFileUri = fileUri;
|
||||
pickerInitialUri = fileUri;
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MainActivity.class.getName()).log(Level.SEVERE, null, ex);
|
||||
private void fallBackSaveAs() {
|
||||
boolean permissionGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
|
||||
if (permissionGranted) {
|
||||
SaveFileDialog dialog = new SaveFileDialog();
|
||||
dialog.setStyle(DialogFragment.STYLE_NO_TITLE, R.style.AppTheme);
|
||||
dialog.show(getSupportFragmentManager(), SaveFileDialog.class.getName());
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
|
||||
long cursorDataPosition = savedInstanceState.getLong(CURSOR_POSITION_TAG);
|
||||
int cursorOffset = savedInstanceState.getInt(CURSOR_OFFSET_TAG);
|
||||
int cursorSection = savedInstanceState.getInt(CURSOR_SECTION_TAG);
|
||||
codeArea.setActiveCaretPosition(new DefaultCodeAreaCaretPosition(cursorDataPosition, cursorOffset, cursorSection == 0 ? BasicCodeAreaSection.CODE_MATRIX : BasicCodeAreaSection.TEXT_PREVIEW));
|
||||
|
||||
long scrollRowPosition = savedInstanceState.getLong(SCROLL_ROW_POSITION_TAG);
|
||||
int scrollRowOffset = savedInstanceState.getInt(SCROLL_ROW_OFFSET_TAG);
|
||||
int scrollCharPosition = savedInstanceState.getInt(SCROLL_CHAR_POSITION_TAG);
|
||||
int scrollCharOffset = savedInstanceState.getInt(SCROLL_CHAR_OFFSET_TAG);
|
||||
codeArea.setScrollPosition(new CodeAreaScrollPosition(scrollRowPosition, scrollRowOffset, scrollCharPosition, scrollCharOffset));
|
||||
|
||||
long selectionStart = savedInstanceState.getLong(SELECTION_START_TAG);
|
||||
long selectionEnd = savedInstanceState.getLong(SELECTION_END_TAG);
|
||||
codeArea.setSelection(new SelectionRange(selectionStart, selectionEnd));
|
||||
boolean permissionGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
|
||||
if (!permissionGranted) {
|
||||
Toast.makeText(this, R.string.storage_permission_is_not_granted, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
SelectionRange selection = codeArea.getSelection();
|
||||
outState.putLong(SELECTION_START_TAG, selection.getStart());
|
||||
outState.putLong(SELECTION_END_TAG, selection.getEnd());
|
||||
|
||||
CodeAreaScrollPosition scrollPosition = codeArea.getScrollPosition();
|
||||
outState.putLong(SCROLL_ROW_POSITION_TAG, scrollPosition.getRowPosition());
|
||||
outState.putInt(SCROLL_ROW_OFFSET_TAG, scrollPosition.getRowOffset());
|
||||
outState.putInt(SCROLL_CHAR_POSITION_TAG, scrollPosition.getCharPosition());
|
||||
outState.putInt(SCROLL_CHAR_OFFSET_TAG, scrollPosition.getCharOffset());
|
||||
|
||||
CodeAreaCaretPosition caretPosition = codeArea.getActiveCaretPosition();
|
||||
outState.putLong(CURSOR_POSITION_TAG, caretPosition.getDataPosition());
|
||||
outState.putInt(CURSOR_OFFSET_TAG, caretPosition.getCodeOffset());
|
||||
outState.putInt(CURSOR_SECTION_TAG, ((BasicCodeAreaSection) caretPosition.getSection().orElse(BasicCodeAreaSection.CODE_MATRIX)).ordinal());
|
||||
}
|
||||
|
||||
private void showPermissionError() {
|
||||
Toast.makeText(this, "Storage permission is not granted", Toast.LENGTH_LONG).show();
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
processIntent(intent);
|
||||
}
|
||||
|
||||
public void updateStatus() {
|
||||
@@ -776,7 +885,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
long dataSize = codeArea.getDataSize();
|
||||
binaryStatus.setCurrentDocumentSize(dataSize, documentOriginalSize);
|
||||
binaryStatus.setCurrentDocumentSize(dataSize, fileHandler.getDocumentOriginalSize());
|
||||
}
|
||||
|
||||
private void updateCurrentCaretPosition() {
|
||||
@@ -834,6 +943,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private void updateViewActionsState() {
|
||||
menu.findItem(R.id.code_colorization).setChecked(appPreferences.getCodeAreaPreferences().isCodeColorization());
|
||||
menu.findItem(R.id.non_printable_characters).setChecked(appPreferences.getCodeAreaPreferences().isShowNonprintables());
|
||||
int bytesPerRow = appPreferences.getCodeAreaPreferences().getMaxBytesPerRow();
|
||||
switch (bytesPerRow) {
|
||||
case 0: {
|
||||
@@ -861,14 +971,15 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private void updateUndoState() {
|
||||
MenuItem saveMenuItem = menu.findItem(R.id.action_save);
|
||||
saveMenuItem.setEnabled(currentFileUri == null || undoRedo.isModified());
|
||||
Uri currentFileUri = fileHandler.getCurrentFileUri();
|
||||
saveMenuItem.setEnabled(currentFileUri == null || fileHandler.getUndoRedo().isModified());
|
||||
|
||||
boolean canUndo = undoRedo.canUndo();
|
||||
boolean canUndo = fileHandler.getUndoRedo().canUndo();
|
||||
MenuItem undoMenuItem = menu.findItem(R.id.action_undo);
|
||||
undoMenuItem.setEnabled(canUndo);
|
||||
// TODO undoMenuItem.setIconTintList(new ColorStateList(ColorStateList.));
|
||||
|
||||
boolean canRedo = undoRedo.canRedo();
|
||||
boolean canRedo = fileHandler.getUndoRedo().canRedo();
|
||||
MenuItem redoMenuItem = menu.findItem(R.id.action_redo);
|
||||
redoMenuItem.setEnabled(canRedo);
|
||||
}
|
||||
@@ -880,7 +991,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
openFile(data.getData());
|
||||
fileHandler.openFile(getContentResolver(), data.getData());
|
||||
}
|
||||
|
||||
private void saveFileResultCallback(ActivityResult activityResult) {
|
||||
@@ -890,16 +1001,37 @@ public class MainActivity extends AppCompatActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
saveFile(data.getData());
|
||||
fileHandler.saveFile(getContentResolver(), data.getData());
|
||||
if (postSaveAsAction != null) {
|
||||
postSaveAsAction.run();
|
||||
postSaveAsAction = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy support for file dialog using external library.
|
||||
*
|
||||
* @param dialog file dialog
|
||||
* @param file selected file
|
||||
*/
|
||||
@Override
|
||||
public void onFileSelected(FileDialog dialog, File file) {
|
||||
if (dialog instanceof OpenFileDialog) {
|
||||
fileHandler.openFile(getContentResolver(), Uri.fromFile(file));
|
||||
} else {
|
||||
fileHandler.saveFile(getContentResolver(), Uri.fromFile(file));
|
||||
if (postSaveAsAction != null) {
|
||||
postSaveAsAction.run();
|
||||
postSaveAsAction = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void settingsResultCallback(ActivityResult activityResult) {
|
||||
applySettings();
|
||||
updateViewActionsState();
|
||||
if (menu != null) {
|
||||
updateViewActionsState();
|
||||
}
|
||||
}
|
||||
|
||||
public void buttonAction0(View view) {
|
||||
@@ -1005,4 +1137,9 @@ public class MainActivity extends AppCompatActivity {
|
||||
public void buttonActionTab(View view) {
|
||||
codeArea.getCommandHandler().keyPressed(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_TAB));
|
||||
}
|
||||
|
||||
public static boolean isGoogleTV(Context context) {
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
return pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,11 @@ import java.util.Locale;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
/**
|
||||
* Settings activity.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class SettingsActivity extends AppCompatActivity implements
|
||||
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
|
||||
@@ -62,6 +67,7 @@ public class SettingsActivity extends AppCompatActivity implements
|
||||
public static final String CODE_TYPE_KEY = "code_type";
|
||||
public static final String HEX_CHARACTERS_CASE = "hex_characters_case";
|
||||
public static final String CODE_COLORIZATION = "code_colorization";
|
||||
public static final String NONPRINTABLE_CHARACTERS = "nonprintable_characters";
|
||||
|
||||
private BinaryEditorPreferences appPreferences;
|
||||
|
||||
@@ -224,6 +230,7 @@ public class SettingsActivity extends AppCompatActivity implements
|
||||
((ListPreference) findPreference(CODE_TYPE_KEY)).setValue(codeAreaPreferences.getCodeType().name());
|
||||
((ListPreference) findPreference(HEX_CHARACTERS_CASE)).setValue(codeAreaPreferences.getCodeCharactersCase().name());
|
||||
((TwoStatePreference) findPreference(CODE_COLORIZATION)).setChecked(codeAreaPreferences.isCodeColorization());
|
||||
((TwoStatePreference) findPreference(NONPRINTABLE_CHARACTERS)).setChecked(codeAreaPreferences.isShowNonprintables());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -240,6 +247,7 @@ public class SettingsActivity extends AppCompatActivity implements
|
||||
codeAreaPreferences.setCodeType(CodeType.valueOf(((ListPreference) findPreference(CODE_TYPE_KEY)).getValue()));
|
||||
codeAreaPreferences.setCodeCharactersCase(CodeCharactersCase.valueOf(((ListPreference) findPreference(HEX_CHARACTERS_CASE)).getValue()));
|
||||
codeAreaPreferences.setCodeColorization(((TwoStatePreference) findPreference(CODE_COLORIZATION)).isChecked());
|
||||
codeAreaPreferences.setShowNonprintables(((TwoStatePreference) findPreference(NONPRINTABLE_CHARACTERS)).isChecked());
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public interface CodeAreaOptions {
|
||||
|
||||
boolean isCodeColorization();
|
||||
|
||||
boolean isShowUnprintables();
|
||||
boolean isShowNonprintables();
|
||||
|
||||
void setCodeCharactersCase(CodeCharactersCase codeCharactersCase);
|
||||
|
||||
@@ -73,7 +73,7 @@ public interface CodeAreaOptions {
|
||||
|
||||
void setRowWrappingMode(RowWrappingMode rowWrappingMode);
|
||||
|
||||
void setShowUnprintables(boolean showUnprintables);
|
||||
void setShowNonprintables(boolean showUnprintables);
|
||||
|
||||
void setViewMode(CodeAreaViewMode viewMode);
|
||||
}
|
||||
|
||||
+17
-7
@@ -19,10 +19,13 @@ import org.exbin.bined.CodeCharactersCase;
|
||||
import org.exbin.bined.CodeType;
|
||||
import org.exbin.bined.PositionCodeType;
|
||||
import org.exbin.bined.RowWrappingMode;
|
||||
import org.exbin.bined.android.CodeAreaAndroidUtils;
|
||||
import org.exbin.bined.android.basic.CodeArea;
|
||||
import org.exbin.bined.android.capability.ColorAssessorPainterCapable;
|
||||
import org.exbin.bined.basic.CodeAreaViewMode;
|
||||
import org.exbin.bined.editor.android.options.CodeAreaOptions;
|
||||
import org.exbin.bined.highlight.android.HighlightNonAsciiCodeAreaPainter;
|
||||
import org.exbin.bined.highlight.android.NonAsciiCodeAreaColorAssessor;
|
||||
import org.exbin.bined.highlight.android.NonprintablesCodeAreaAssessor;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -39,7 +42,7 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||
public class CodeAreaPreferences implements CodeAreaOptions {
|
||||
|
||||
public static final String PREFERENCES_CODE_TYPE = "codeType";
|
||||
public static final String PREFERENCES_SHOW_UNPRINTABLES = "showNonpritables";
|
||||
public static final String PREFERENCES_SHOW_NONPRINTABLES = "showNonpritables";
|
||||
public static final String PREFERENCES_BYTES_PER_LINE = "bytesPerLine";
|
||||
public static final String PREFERENCES_LINE_NUMBERS_LENGTH_TYPE = "lineNumbersLengthType";
|
||||
public static final String PREFERENCES_LINE_NUMBERS_LENGTH = "lineNumbersLength";
|
||||
@@ -77,13 +80,13 @@ public class CodeAreaPreferences implements CodeAreaOptions {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowUnprintables() {
|
||||
return preferences.getBoolean(PREFERENCES_SHOW_UNPRINTABLES, false);
|
||||
public boolean isShowNonprintables() {
|
||||
return preferences.getBoolean(PREFERENCES_SHOW_NONPRINTABLES, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShowUnprintables(boolean showUnprintables) {
|
||||
preferences.putBoolean(PREFERENCES_SHOW_UNPRINTABLES, showUnprintables);
|
||||
public void setShowNonprintables(boolean showNonprintables) {
|
||||
preferences.putBoolean(PREFERENCES_SHOW_NONPRINTABLES, showNonprintables);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -208,6 +211,13 @@ public class CodeAreaPreferences implements CodeAreaOptions {
|
||||
codeArea.setCodeCharactersCase(getCodeCharactersCase());
|
||||
codeArea.setRowWrapping(getRowWrappingMode());
|
||||
codeArea.setMaxBytesPerRow(getMaxBytesPerRow());
|
||||
((HighlightNonAsciiCodeAreaPainter) codeArea.getPainter()).setNonAsciiHighlightingEnabled(isCodeColorization());
|
||||
NonprintablesCodeAreaAssessor nonprintablesCodeAreaAssessor = CodeAreaAndroidUtils.findColorAssessor((ColorAssessorPainterCapable) codeArea.getPainter(), NonprintablesCodeAreaAssessor.class);
|
||||
if (nonprintablesCodeAreaAssessor != null) {
|
||||
nonprintablesCodeAreaAssessor.setShowNonprintables(isShowNonprintables());
|
||||
}
|
||||
NonAsciiCodeAreaColorAssessor nonAsciiColorAssessor = CodeAreaAndroidUtils.findColorAssessor((ColorAssessorPainterCapable) codeArea.getPainter(), NonAsciiCodeAreaColorAssessor.class);
|
||||
if (nonAsciiColorAssessor != null) {
|
||||
nonAsciiColorAssessor.setNonAsciiHighlightingEnabled(isCodeColorization());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,11 @@ import java.util.SortedMap;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
/**
|
||||
* Application encoding preferences.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class EncodingPreference extends EditTextPreference {
|
||||
|
||||
|
||||
@@ -28,6 +28,11 @@ import org.exbin.bined.editor.android.R;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
/**
|
||||
* Application font preferences.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class FontPreference extends EditTextPreference {
|
||||
|
||||
|
||||
+35
-33
@@ -19,9 +19,11 @@ import org.exbin.auxiliary.binary_data.BinaryData;
|
||||
import org.exbin.auxiliary.binary_data.EditableBinaryData;
|
||||
import org.exbin.bined.CharsetStreamTranslator;
|
||||
import org.exbin.bined.CodeAreaUtils;
|
||||
import org.exbin.bined.android.CodeAreaAndroidUtils;
|
||||
import org.exbin.bined.android.basic.CodeArea;
|
||||
import org.exbin.bined.highlight.android.HighlightCodeAreaPainter;
|
||||
import org.exbin.bined.highlight.android.HighlightNonAsciiCodeAreaPainter;
|
||||
import org.exbin.bined.android.capability.ColorAssessorPainterCapable;
|
||||
import org.exbin.bined.highlight.android.SearchCodeAreaColorAssessor;
|
||||
import org.exbin.bined.highlight.android.SearchMatch;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
@@ -50,11 +52,11 @@ public class BinarySearchServiceImpl implements BinarySearchService {
|
||||
|
||||
@Override
|
||||
public void performFind(SearchParameters searchParameters, SearchStatusListener searchStatusListener) {
|
||||
HighlightNonAsciiCodeAreaPainter painter = (HighlightNonAsciiCodeAreaPainter) codeArea.getPainter();
|
||||
SearchCodeAreaColorAssessor searchAssessor = CodeAreaAndroidUtils.findColorAssessor((ColorAssessorPainterCapable) codeArea.getPainter(), SearchCodeAreaColorAssessor.class);
|
||||
SearchCondition condition = searchParameters.getCondition();
|
||||
searchStatusListener.clearStatus();
|
||||
if (condition.isEmpty()) {
|
||||
painter.clearMatches();
|
||||
searchAssessor.clearMatches();
|
||||
codeArea.repaint();
|
||||
return;
|
||||
}
|
||||
@@ -113,7 +115,7 @@ public class BinarySearchServiceImpl implements BinarySearchService {
|
||||
* Performs search by binary data.
|
||||
*/
|
||||
private void searchForBinaryData(SearchParameters searchParameters, SearchStatusListener searchStatusListener) {
|
||||
HighlightNonAsciiCodeAreaPainter painter = (HighlightNonAsciiCodeAreaPainter) codeArea.getPainter();
|
||||
SearchCodeAreaColorAssessor searchAssessor = CodeAreaAndroidUtils.findColorAssessor((ColorAssessorPainterCapable) codeArea.getPainter(), SearchCodeAreaColorAssessor.class);
|
||||
SearchCondition condition = searchParameters.getCondition();
|
||||
long position = searchParameters.getStartPosition();
|
||||
|
||||
@@ -121,7 +123,7 @@ public class BinarySearchServiceImpl implements BinarySearchService {
|
||||
long searchDataSize = searchData.getDataSize();
|
||||
BinaryData data = codeArea.getContentData();
|
||||
|
||||
List<HighlightNonAsciiCodeAreaPainter.SearchMatch> foundMatches = new ArrayList<>();
|
||||
List<SearchMatch> foundMatches = new ArrayList<>();
|
||||
|
||||
long dataSize = data.getDataSize();
|
||||
while (position >= 0 && position <= dataSize - searchDataSize) {
|
||||
@@ -134,7 +136,7 @@ public class BinarySearchServiceImpl implements BinarySearchService {
|
||||
}
|
||||
|
||||
if (matchLength == searchDataSize) {
|
||||
HighlightNonAsciiCodeAreaPainter.SearchMatch match = new HighlightNonAsciiCodeAreaPainter.SearchMatch();
|
||||
SearchMatch match = new SearchMatch();
|
||||
match.setPosition(position);
|
||||
match.setLength(searchDataSize);
|
||||
if (searchParameters.getSearchDirection() == SearchParameters.SearchDirection.BACKWARD) {
|
||||
@@ -151,18 +153,18 @@ public class BinarySearchServiceImpl implements BinarySearchService {
|
||||
position++;
|
||||
}
|
||||
|
||||
painter.setMatches(foundMatches);
|
||||
searchAssessor.setMatches(foundMatches);
|
||||
if (!foundMatches.isEmpty()) {
|
||||
if (searchParameters.getSearchDirection() == SearchParameters.SearchDirection.BACKWARD) {
|
||||
painter.setCurrentMatchIndex(foundMatches.size() - 1);
|
||||
searchAssessor.setCurrentMatchIndex(foundMatches.size() - 1);
|
||||
} else {
|
||||
painter.setCurrentMatchIndex(0);
|
||||
searchAssessor.setCurrentMatchIndex(0);
|
||||
}
|
||||
HighlightNonAsciiCodeAreaPainter.SearchMatch firstMatch = Objects.requireNonNull(painter.getCurrentMatch());
|
||||
SearchMatch firstMatch = Objects.requireNonNull(searchAssessor.getCurrentMatch());
|
||||
codeArea.revealPosition(firstMatch.getPosition(), 0, codeArea.getActiveSection());
|
||||
}
|
||||
lastSearchParameters.setFromParameters(searchParameters);
|
||||
searchStatusListener.setStatus(new FoundMatches(foundMatches.size(), foundMatches.isEmpty() ? -1 : painter.getCurrentMatchIndex()), searchParameters.getMatchMode());
|
||||
searchStatusListener.setStatus(new FoundMatches(foundMatches.size(), foundMatches.isEmpty() ? -1 : searchAssessor.getCurrentMatchIndex()), searchParameters.getMatchMode());
|
||||
codeArea.repaint();
|
||||
}
|
||||
|
||||
@@ -170,7 +172,7 @@ public class BinarySearchServiceImpl implements BinarySearchService {
|
||||
* Performs search by text/characters.
|
||||
*/
|
||||
private void searchForText(SearchParameters searchParameters, SearchStatusListener searchStatusListener) {
|
||||
HighlightNonAsciiCodeAreaPainter painter = (HighlightNonAsciiCodeAreaPainter) codeArea.getPainter();
|
||||
SearchCodeAreaColorAssessor searchAssessor = CodeAreaAndroidUtils.findColorAssessor((ColorAssessorPainterCapable) codeArea.getPainter(), SearchCodeAreaColorAssessor.class);
|
||||
SearchCondition condition = searchParameters.getCondition();
|
||||
|
||||
long position = searchParameters.getStartPosition();
|
||||
@@ -183,7 +185,7 @@ public class BinarySearchServiceImpl implements BinarySearchService {
|
||||
long searchDataSize = findText.length();
|
||||
BinaryData data = codeArea.getContentData();
|
||||
|
||||
List<HighlightNonAsciiCodeAreaPainter.SearchMatch> foundMatches = new ArrayList<>();
|
||||
List<SearchMatch> foundMatches = new ArrayList<>();
|
||||
|
||||
Charset charset = codeArea.getCharset();
|
||||
int maxBytesPerChar;
|
||||
@@ -221,7 +223,7 @@ public class BinarySearchServiceImpl implements BinarySearchService {
|
||||
}
|
||||
|
||||
if (matchCharLength == findText.length()) {
|
||||
HighlightNonAsciiCodeAreaPainter.SearchMatch match = new HighlightNonAsciiCodeAreaPainter.SearchMatch();
|
||||
SearchMatch match = new SearchMatch();
|
||||
match.setPosition(position);
|
||||
match.setLength(matchLength);
|
||||
if (searchParameters.getSearchDirection() == SearchParameters.SearchDirection.BACKWARD) {
|
||||
@@ -249,41 +251,41 @@ public class BinarySearchServiceImpl implements BinarySearchService {
|
||||
}
|
||||
}
|
||||
|
||||
painter.setMatches(foundMatches);
|
||||
searchAssessor.setMatches(foundMatches);
|
||||
if (!foundMatches.isEmpty()) {
|
||||
if (searchParameters.getSearchDirection() == SearchParameters.SearchDirection.BACKWARD) {
|
||||
painter.setCurrentMatchIndex(foundMatches.size() - 1);
|
||||
searchAssessor.setCurrentMatchIndex(foundMatches.size() - 1);
|
||||
} else {
|
||||
painter.setCurrentMatchIndex(0);
|
||||
searchAssessor.setCurrentMatchIndex(0);
|
||||
}
|
||||
HighlightNonAsciiCodeAreaPainter.SearchMatch firstMatch = painter.getCurrentMatch();
|
||||
SearchMatch firstMatch = searchAssessor.getCurrentMatch();
|
||||
codeArea.revealPosition(firstMatch.getPosition(), 0, codeArea.getActiveSection());
|
||||
}
|
||||
lastSearchParameters.setFromParameters(searchParameters);
|
||||
searchStatusListener.setStatus(new FoundMatches(foundMatches.size(), foundMatches.isEmpty() ? -1 : painter.getCurrentMatchIndex()), searchParameters.getMatchMode());
|
||||
searchStatusListener.setStatus(new FoundMatches(foundMatches.size(), foundMatches.isEmpty() ? -1 : searchAssessor.getCurrentMatchIndex()), searchParameters.getMatchMode());
|
||||
codeArea.repaint();
|
||||
}
|
||||
|
||||
public void setMatchPosition(int matchPosition) {
|
||||
HighlightNonAsciiCodeAreaPainter painter = (HighlightNonAsciiCodeAreaPainter) codeArea.getPainter();
|
||||
painter.setCurrentMatchIndex(matchPosition);
|
||||
HighlightNonAsciiCodeAreaPainter.SearchMatch currentMatch = painter.getCurrentMatch();
|
||||
SearchCodeAreaColorAssessor searchAssessor = CodeAreaAndroidUtils.findColorAssessor((ColorAssessorPainterCapable) codeArea.getPainter(), SearchCodeAreaColorAssessor.class);
|
||||
searchAssessor.setCurrentMatchIndex(matchPosition);
|
||||
SearchMatch currentMatch = searchAssessor.getCurrentMatch();
|
||||
codeArea.revealPosition(currentMatch.getPosition(), 0, codeArea.getActiveSection());
|
||||
codeArea.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performFindAgain(SearchStatusListener searchStatusListener) {
|
||||
HighlightNonAsciiCodeAreaPainter painter = (HighlightNonAsciiCodeAreaPainter) codeArea.getPainter();
|
||||
List<HighlightCodeAreaPainter.SearchMatch> foundMatches = painter.getMatches();
|
||||
SearchCodeAreaColorAssessor searchAssessor = CodeAreaAndroidUtils.findColorAssessor((ColorAssessorPainterCapable) codeArea.getPainter(), SearchCodeAreaColorAssessor.class);
|
||||
List<SearchMatch> foundMatches = searchAssessor.getMatches();
|
||||
int matchesCount = foundMatches.size();
|
||||
if (matchesCount > 0) {
|
||||
switch (lastSearchParameters.getMatchMode()) {
|
||||
case MULTIPLE:
|
||||
if (matchesCount > 1) {
|
||||
int currentMatchIndex = painter.getCurrentMatchIndex();
|
||||
int currentMatchIndex = searchAssessor.getCurrentMatchIndex();
|
||||
setMatchPosition(currentMatchIndex < matchesCount - 1 ? currentMatchIndex + 1 : 0);
|
||||
searchStatusListener.setStatus(new FoundMatches(foundMatches.size(), painter.getCurrentMatchIndex()), lastSearchParameters.getMatchMode());
|
||||
searchStatusListener.setStatus(new FoundMatches(foundMatches.size(), searchAssessor.getCurrentMatchIndex()), lastSearchParameters.getMatchMode());
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -293,7 +295,7 @@ public class BinarySearchServiceImpl implements BinarySearchService {
|
||||
lastSearchParameters.setStartPosition(foundMatches.get(0).getPosition() + 1);
|
||||
break;
|
||||
case BACKWARD:
|
||||
HighlightCodeAreaPainter.SearchMatch match = foundMatches.get(0);
|
||||
SearchMatch match = foundMatches.get(0);
|
||||
lastSearchParameters.setStartPosition(match.getPosition() - 1);
|
||||
break;
|
||||
}
|
||||
@@ -319,8 +321,8 @@ public class BinarySearchServiceImpl implements BinarySearchService {
|
||||
@Override
|
||||
public void performReplace(SearchParameters searchParameters, ReplaceParameters replaceParameters) {
|
||||
SearchCondition replaceCondition = replaceParameters.getCondition();
|
||||
HighlightNonAsciiCodeAreaPainter painter = (HighlightNonAsciiCodeAreaPainter) codeArea.getPainter();
|
||||
HighlightNonAsciiCodeAreaPainter.SearchMatch currentMatch = painter.getCurrentMatch();
|
||||
SearchCodeAreaColorAssessor searchAssessor = CodeAreaAndroidUtils.findColorAssessor((ColorAssessorPainterCapable) codeArea.getPainter(), SearchCodeAreaColorAssessor.class);
|
||||
SearchMatch currentMatch = searchAssessor.getCurrentMatch();
|
||||
if (currentMatch != null) {
|
||||
EditableBinaryData editableData = ((EditableBinaryData) codeArea.getContentData());
|
||||
editableData.remove(currentMatch.getPosition(), currentMatch.getLength());
|
||||
@@ -329,7 +331,7 @@ public class BinarySearchServiceImpl implements BinarySearchService {
|
||||
} else {
|
||||
editableData.insert(currentMatch.getPosition(), replaceCondition.getSearchText().getBytes(codeArea.getCharset()));
|
||||
}
|
||||
painter.getMatches().remove(currentMatch);
|
||||
searchAssessor.getMatches().remove(currentMatch);
|
||||
codeArea.repaint();
|
||||
}
|
||||
}
|
||||
@@ -342,7 +344,7 @@ public class BinarySearchServiceImpl implements BinarySearchService {
|
||||
|
||||
@Override
|
||||
public void clearMatches() {
|
||||
HighlightNonAsciiCodeAreaPainter painter = (HighlightNonAsciiCodeAreaPainter) codeArea.getPainter();
|
||||
painter.clearMatches();
|
||||
SearchCodeAreaColorAssessor searchAssessor = CodeAreaAndroidUtils.findColorAssessor((ColorAssessorPainterCapable) codeArea.getPainter(), SearchCodeAreaColorAssessor.class);
|
||||
searchAssessor.clearMatches();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.highlight.android;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.basic.BasicCodeAreaSection;
|
||||
import org.exbin.bined.CodeAreaSection;
|
||||
import org.exbin.bined.android.CodeAreaCore;
|
||||
import org.exbin.bined.android.basic.DefaultCodeAreaPainter;
|
||||
|
||||
/**
|
||||
* Hexadecimal component painter supporting search matches highlighting.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class HighlightCodeAreaPainter extends DefaultCodeAreaPainter {
|
||||
|
||||
/**
|
||||
* Matches must be ordered by position.
|
||||
*/
|
||||
private final List<SearchMatch> matches = new ArrayList<>();
|
||||
private int currentMatchIndex = -1;
|
||||
private int matchIndex = 0;
|
||||
private long matchPosition = -1;
|
||||
|
||||
private Integer foundMatchesColor;
|
||||
private Integer currentMatchColor;
|
||||
|
||||
public HighlightCodeAreaPainter(CodeAreaCore codeArea) {
|
||||
super(codeArea);
|
||||
|
||||
foundMatchesColor = Color.rgb(180, 255, 180);
|
||||
currentMatchColor = Color.rgb(255, 210, 180);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintMainArea(Canvas g) {
|
||||
matchIndex = 0;
|
||||
super.paintMainArea(g);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer getPositionTextColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section) {
|
||||
return super.getPositionTextColor(rowDataPosition, byteOnRow, charOnRow, section);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer getPositionBackgroundColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section) {
|
||||
if (!matches.isEmpty() && charOnRow < getCharactersPerRow() - 1) {
|
||||
long dataPosition = rowDataPosition + byteOnRow;
|
||||
if (currentMatchIndex >= 0) {
|
||||
SearchMatch currentMatch = matches.get(currentMatchIndex);
|
||||
if (dataPosition >= currentMatch.position && dataPosition < currentMatch.position + currentMatch.length
|
||||
&& (section == BasicCodeAreaSection.TEXT_PREVIEW || charOnRow != ((currentMatch.position + currentMatch.length) - rowDataPosition) * getCharactersPerRow() - 1)) {
|
||||
return currentMatchColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchPosition < rowDataPosition) {
|
||||
matchIndex = 0;
|
||||
}
|
||||
int lineMatchIndex = matchIndex;
|
||||
while (lineMatchIndex < matches.size()) {
|
||||
SearchMatch match = matches.get(lineMatchIndex);
|
||||
if (dataPosition >= match.position && dataPosition < match.position + match.length
|
||||
&& (section == BasicCodeAreaSection.TEXT_PREVIEW || charOnRow != ((match.position + match.length) - rowDataPosition) * getCharactersPerRow() - 1)) {
|
||||
if (byteOnRow == 0) {
|
||||
matchIndex = lineMatchIndex;
|
||||
matchPosition = match.position;
|
||||
}
|
||||
return foundMatchesColor;
|
||||
}
|
||||
|
||||
if (match.position > dataPosition) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (byteOnRow == 0) {
|
||||
matchIndex = lineMatchIndex;
|
||||
matchPosition = match.position;
|
||||
}
|
||||
lineMatchIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return super.getPositionBackgroundColor(rowDataPosition, byteOnRow, charOnRow, section);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<SearchMatch> getMatches() {
|
||||
return matches;
|
||||
}
|
||||
|
||||
public void setMatches(List<SearchMatch> matches) {
|
||||
this.matches.clear();
|
||||
this.matches.addAll(matches);
|
||||
currentMatchIndex = -1;
|
||||
}
|
||||
|
||||
public void clearMatches() {
|
||||
this.matches.clear();
|
||||
currentMatchIndex = -1;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SearchMatch getCurrentMatch() {
|
||||
if (currentMatchIndex >= 0) {
|
||||
return matches.get(currentMatchIndex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getCurrentMatchIndex() {
|
||||
return currentMatchIndex;
|
||||
}
|
||||
|
||||
public void setCurrentMatchIndex(int currentMatchIndex) {
|
||||
this.currentMatchIndex = currentMatchIndex;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Integer getFoundMatchesBackgroundColor() {
|
||||
return foundMatchesColor;
|
||||
}
|
||||
|
||||
public void setFoundMatchesBackgroundColor(Integer foundMatchesBackgroundColor) {
|
||||
this.foundMatchesColor = foundMatchesBackgroundColor;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Integer getCurrentMatchBackgroundColor() {
|
||||
return currentMatchColor;
|
||||
}
|
||||
|
||||
public void setCurrentMatchBackgroundColor(Integer currentMatchBackgroundColor) {
|
||||
this.currentMatchColor = currentMatchBackgroundColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple POJO class for search match.
|
||||
*/
|
||||
public static class SearchMatch {
|
||||
|
||||
private long position;
|
||||
private long length;
|
||||
|
||||
public SearchMatch() {
|
||||
}
|
||||
|
||||
public SearchMatch(long position, long length) {
|
||||
this.position = position;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public long getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(long position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(long length) {
|
||||
this.length = length;
|
||||
}
|
||||
}
|
||||
}
|
||||
-158
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.highlight.android;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.basic.BasicCodeAreaSection;
|
||||
import org.exbin.bined.CodeAreaSection;
|
||||
import org.exbin.bined.android.CodeAreaCore;
|
||||
|
||||
/**
|
||||
* Experimental support for highlighting of non-ascii characters.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class HighlightNonAsciiCodeAreaPainter extends HighlightCodeAreaPainter {
|
||||
|
||||
private Integer controlCodes;
|
||||
private Integer upperCodes;
|
||||
private Integer textColor;
|
||||
private boolean nonAsciiHighlightingEnabled = true;
|
||||
|
||||
public HighlightNonAsciiCodeAreaPainter(CodeAreaCore codeArea) {
|
||||
super(codeArea);
|
||||
|
||||
textColor = Color.BLACK; // TODO codeArea.getForeground(); //MainColors().getTextColor();
|
||||
if (textColor == null) {
|
||||
textColor = Color.BLACK;
|
||||
}
|
||||
|
||||
int controlCodesRed = Color.red(textColor);
|
||||
int controlCodesRedDiff = 0;
|
||||
if (controlCodesRed > 32) {
|
||||
if (controlCodesRed > 192) {
|
||||
controlCodesRedDiff = controlCodesRed - 192;
|
||||
}
|
||||
controlCodesRed = 255;
|
||||
} else {
|
||||
controlCodesRed += 224;
|
||||
}
|
||||
|
||||
int controlCodesBlue = Color.blue(textColor);
|
||||
int controlCodesBlueDiff = 0;
|
||||
if (controlCodesBlue > 32) {
|
||||
if (controlCodesBlue > 192) {
|
||||
controlCodesBlueDiff = controlCodesBlue - 192;
|
||||
}
|
||||
controlCodesBlue = 255;
|
||||
} else {
|
||||
controlCodesBlue += 224;
|
||||
}
|
||||
|
||||
controlCodes = Color.rgb(
|
||||
controlCodesRed,
|
||||
downShift(Color.green(textColor), controlCodesBlueDiff + controlCodesRedDiff),
|
||||
controlCodesBlue);
|
||||
|
||||
int upperCodesGreen = Color.green(textColor);
|
||||
int upperCodesGreenDiff = 0;
|
||||
if (upperCodesGreen > 64) {
|
||||
if (upperCodesGreen > 192) {
|
||||
upperCodesGreenDiff = upperCodesGreen - 192;
|
||||
}
|
||||
|
||||
upperCodesGreen = 255;
|
||||
} else {
|
||||
upperCodesGreen += 192;
|
||||
}
|
||||
|
||||
int upperCodesBlue = Color.blue(textColor);
|
||||
int upperCodesBlueDiff = 0;
|
||||
if (upperCodesBlue > 64) {
|
||||
if (upperCodesBlue > 192) {
|
||||
upperCodesBlueDiff = upperCodesBlue - 192;
|
||||
}
|
||||
|
||||
upperCodesBlue = 255;
|
||||
} else {
|
||||
upperCodesBlue += 192;
|
||||
}
|
||||
|
||||
upperCodes = Color.rgb(
|
||||
downShift(Color.red(textColor), upperCodesGreenDiff + upperCodesBlueDiff),
|
||||
upperCodesGreen, upperCodesBlue);
|
||||
}
|
||||
|
||||
private int downShift(int color, int diff) {
|
||||
if (color < diff) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return color - diff;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer getPositionTextColor(long rowDataPosition, int byteOnRow, int charOnRow, @Nonnull CodeAreaSection section) {
|
||||
Integer color = super.getPositionTextColor(rowDataPosition, byteOnRow, charOnRow, section);
|
||||
if (nonAsciiHighlightingEnabled && section == BasicCodeAreaSection.CODE_MATRIX) {
|
||||
if (color == null || textColor.equals(color)) {
|
||||
long dataPosition = rowDataPosition + byteOnRow;
|
||||
if (dataPosition < codeArea.getDataSize()) {
|
||||
byte value = codeArea.getContentData().getByte(dataPosition);
|
||||
if (value < 0) {
|
||||
color = upperCodes;
|
||||
} else if (value < 0x20) {
|
||||
color = controlCodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Integer getControlCodes() {
|
||||
return controlCodes;
|
||||
}
|
||||
|
||||
public void setControlCodes(Integer controlCodes) {
|
||||
this.controlCodes = controlCodes;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Integer getUpperCodes() {
|
||||
return upperCodes;
|
||||
}
|
||||
|
||||
public void setUpperCodes(Integer upperCodes) {
|
||||
this.upperCodes = upperCodes;
|
||||
}
|
||||
|
||||
public boolean isNonAsciiHighlightingEnabled() {
|
||||
return nonAsciiHighlightingEnabled;
|
||||
}
|
||||
|
||||
public void setNonAsciiHighlightingEnabled(boolean nonAsciiHighlightingEnabled) {
|
||||
this.nonAsciiHighlightingEnabled = nonAsciiHighlightingEnabled;
|
||||
}
|
||||
}
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.highlight.android;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.auxiliary.binary_data.BinaryData;
|
||||
import org.exbin.bined.basic.BasicCodeAreaSection;
|
||||
import org.exbin.bined.CodeAreaSection;
|
||||
import org.exbin.bined.color.CodeAreaBasicColors;
|
||||
import org.exbin.bined.highlight.android.color.CodeAreaColorizationColorType;
|
||||
import org.exbin.bined.android.CodeAreaPaintState;
|
||||
import org.exbin.bined.android.basic.color.CodeAreaColorsProfile;
|
||||
import org.exbin.bined.android.CodeAreaColorAssessor;
|
||||
|
||||
/**
|
||||
* Support for highlighting of non-ascii characters.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class NonAsciiCodeAreaColorAssessor implements CodeAreaColorAssessor {
|
||||
|
||||
protected final CodeAreaColorAssessor parentAssessor;
|
||||
|
||||
@Nullable
|
||||
protected Integer controlCodesColor;
|
||||
@Nullable
|
||||
protected Integer controlCodesBackground;
|
||||
@Nullable
|
||||
protected Integer upperCodesColor;
|
||||
@Nullable
|
||||
protected Integer upperCodesBackground;
|
||||
@Nullable
|
||||
protected Integer textColor;
|
||||
protected boolean nonAsciiHighlightingEnabled = true;
|
||||
|
||||
protected long dataSize;
|
||||
protected BinaryData contentData;
|
||||
|
||||
public NonAsciiCodeAreaColorAssessor(@Nullable CodeAreaColorAssessor parentAssessor) {
|
||||
this.parentAssessor = parentAssessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPaint(CodeAreaPaintState codeAreaPaintState) {
|
||||
CodeAreaColorsProfile colorsProfile = codeAreaPaintState.getColorsProfile();
|
||||
|
||||
dataSize = codeAreaPaintState.getDataSize();
|
||||
contentData = codeAreaPaintState.getContentData();
|
||||
|
||||
textColor = colorsProfile.getColor(CodeAreaBasicColors.TEXT_COLOR);
|
||||
if (textColor == null) {
|
||||
textColor = Color.BLACK;
|
||||
}
|
||||
|
||||
controlCodesColor = colorsProfile.getColor(CodeAreaColorizationColorType.CONTROL_CODES_COLOR);
|
||||
if (controlCodesColor == null) {
|
||||
int controlCodesRed = Color.red(textColor);
|
||||
int controlCodesRedDiff = 0;
|
||||
if (controlCodesRed > 32) {
|
||||
if (controlCodesRed > 192) {
|
||||
controlCodesRedDiff = controlCodesRed - 192;
|
||||
}
|
||||
controlCodesRed = 255;
|
||||
} else {
|
||||
controlCodesRed += 224;
|
||||
}
|
||||
|
||||
int controlCodesBlue = Color.blue(textColor);
|
||||
int controlCodesBlueDiff = 0;
|
||||
if (controlCodesBlue > 32) {
|
||||
if (controlCodesBlue > 192) {
|
||||
controlCodesBlueDiff = controlCodesBlue - 192;
|
||||
}
|
||||
controlCodesBlue = 255;
|
||||
} else {
|
||||
controlCodesBlue += 224;
|
||||
}
|
||||
|
||||
controlCodesColor = Color.rgb(
|
||||
controlCodesRed,
|
||||
downShift(Color.green(textColor), controlCodesBlueDiff + controlCodesRedDiff),
|
||||
controlCodesBlue);
|
||||
}
|
||||
controlCodesBackground = colorsProfile.getColor(CodeAreaColorizationColorType.CONTROL_CODES_BACKGROUND);
|
||||
|
||||
upperCodesColor = colorsProfile.getColor(CodeAreaColorizationColorType.UPPER_CODES_COLOR);
|
||||
if (upperCodesColor == null) {
|
||||
int upperCodesGreen = Color.green(textColor);
|
||||
int upperCodesGreenDiff = 0;
|
||||
if (upperCodesGreen > 64) {
|
||||
if (upperCodesGreen > 192) {
|
||||
upperCodesGreenDiff = upperCodesGreen - 192;
|
||||
}
|
||||
|
||||
upperCodesGreen = 255;
|
||||
} else {
|
||||
upperCodesGreen += 192;
|
||||
}
|
||||
|
||||
int upperCodesBlue = Color.blue(textColor);
|
||||
int upperCodesBlueDiff = 0;
|
||||
if (upperCodesBlue > 64) {
|
||||
if (upperCodesBlue > 192) {
|
||||
upperCodesBlueDiff = upperCodesBlue - 192;
|
||||
}
|
||||
|
||||
upperCodesBlue = 255;
|
||||
} else {
|
||||
upperCodesBlue += 192;
|
||||
}
|
||||
|
||||
upperCodesColor = Color.rgb(
|
||||
downShift(Color.red(textColor), upperCodesGreenDiff + upperCodesBlueDiff),
|
||||
upperCodesGreen, upperCodesBlue);
|
||||
}
|
||||
upperCodesBackground = colorsProfile.getColor(CodeAreaColorizationColorType.UPPER_CODES_BACKGROUND);
|
||||
|
||||
if (parentAssessor != null) {
|
||||
parentAssessor.startPaint(codeAreaPaintState);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer getPositionTextColor(long rowDataPosition, int byteOnRow, int charOnRow, @Nonnull CodeAreaSection section, boolean inSelection) {
|
||||
Integer color = parentAssessor != null ? parentAssessor.getPositionTextColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection) : null;
|
||||
if (nonAsciiHighlightingEnabled && section == BasicCodeAreaSection.CODE_MATRIX) {
|
||||
if (color == null || textColor.equals(color)) {
|
||||
long dataPosition = rowDataPosition + byteOnRow;
|
||||
if (dataPosition < dataSize) {
|
||||
byte value = contentData.getByte(dataPosition);
|
||||
if (value < 0) {
|
||||
color = upperCodesColor;
|
||||
} else if (value < 0x20) {
|
||||
color = controlCodesColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer getPositionBackgroundColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section, boolean inSelection) {
|
||||
Integer color = parentAssessor != null ? parentAssessor.getPositionBackgroundColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection) : null;
|
||||
if ((upperCodesBackground != null || controlCodesBackground != null) && nonAsciiHighlightingEnabled && section == BasicCodeAreaSection.CODE_MATRIX) {
|
||||
if (color == null || textColor.equals(color)) {
|
||||
long dataPosition = rowDataPosition + byteOnRow;
|
||||
if (dataPosition < dataSize) {
|
||||
byte value = contentData.getByte(dataPosition);
|
||||
if (upperCodesBackground != null && value < 0) {
|
||||
color = upperCodesBackground;
|
||||
} else if (controlCodesBackground != null && value < 0x20) {
|
||||
color = controlCodesBackground;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Optional<CodeAreaColorAssessor> getParentColorAssessor() {
|
||||
return Optional.ofNullable(parentAssessor);
|
||||
}
|
||||
|
||||
public boolean isNonAsciiHighlightingEnabled() {
|
||||
return nonAsciiHighlightingEnabled;
|
||||
}
|
||||
|
||||
public void setNonAsciiHighlightingEnabled(boolean nonAsciiHighlightingEnabled) {
|
||||
this.nonAsciiHighlightingEnabled = nonAsciiHighlightingEnabled;
|
||||
}
|
||||
|
||||
private static int downShift(int color, int diff) {
|
||||
if (color < diff) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return color - diff;
|
||||
}
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.highlight.android;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.CodeAreaSection;
|
||||
import org.exbin.bined.basic.BasicCodeAreaSection;
|
||||
import org.exbin.bined.color.CodeAreaBasicColors;
|
||||
import org.exbin.bined.highlight.android.color.CodeAreaNonprintablesColorType;
|
||||
import org.exbin.bined.android.CodeAreaCharAssessor;
|
||||
import org.exbin.bined.android.CodeAreaPaintState;
|
||||
import org.exbin.bined.android.CodeAreaColorAssessor;
|
||||
import org.exbin.bined.android.basic.color.CodeAreaColorsProfile;
|
||||
|
||||
/**
|
||||
* Code area non-printable characters highlighting.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class NonprintablesCodeAreaAssessor implements CodeAreaColorAssessor, CodeAreaCharAssessor {
|
||||
|
||||
protected final CodeAreaColorAssessor parentColorAssessor;
|
||||
protected final CodeAreaCharAssessor parentCharAssessor;
|
||||
|
||||
@Nullable
|
||||
protected Map<Character, Character> nonprintableCharactersMapping = null;
|
||||
protected boolean showNonprintables = true;
|
||||
|
||||
@Nullable
|
||||
protected Integer nonprintablesColor;
|
||||
@Nullable
|
||||
protected Integer nonprintablesBackground;
|
||||
|
||||
public NonprintablesCodeAreaAssessor(@Nullable CodeAreaColorAssessor parentColorAssessor, @Nullable CodeAreaCharAssessor parentCharAssessor) {
|
||||
this.parentColorAssessor = parentColorAssessor;
|
||||
this.parentCharAssessor = parentCharAssessor;
|
||||
}
|
||||
|
||||
public boolean isShowNonprintables() {
|
||||
return showNonprintables;
|
||||
}
|
||||
|
||||
public void setShowNonprintables(boolean showNonprintables) {
|
||||
this.showNonprintables = showNonprintables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPaint(CodeAreaPaintState codeAreaPaintState) {
|
||||
if (nonprintableCharactersMapping == null) {
|
||||
buildNonprintableCharactersMapping();
|
||||
}
|
||||
|
||||
CodeAreaColorsProfile colorsProfile = codeAreaPaintState.getColorsProfile();
|
||||
nonprintablesColor = colorsProfile.getColor(CodeAreaNonprintablesColorType.NONPRINTABLES_COLOR);
|
||||
if (nonprintablesColor == null) {
|
||||
Integer textColor = colorsProfile.getColor(CodeAreaBasicColors.TEXT_COLOR);
|
||||
nonprintablesColor = Color.rgb(Color.red(textColor), (Color.green(textColor) + 128) % 256, (Color.blue(textColor) + 96) % 256);
|
||||
}
|
||||
nonprintablesBackground = colorsProfile.getColor(CodeAreaNonprintablesColorType.NONPRINTABLES_BACKGROUND);
|
||||
|
||||
if (parentColorAssessor != null) {
|
||||
parentColorAssessor.startPaint(codeAreaPaintState);
|
||||
}
|
||||
|
||||
if (parentCharAssessor != null) {
|
||||
parentCharAssessor.startPaint(codeAreaPaintState);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer getPositionTextColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section, boolean inSelection) {
|
||||
if (showNonprintables && section == BasicCodeAreaSection.TEXT_PREVIEW) {
|
||||
// Cache results to speed up?
|
||||
Character character = parentCharAssessor != null ? parentCharAssessor.getPreviewCharacter(rowDataPosition, byteOnRow, charOnRow, section) : null;
|
||||
if (character != null && nonprintableCharactersMapping.containsKey(character)) {
|
||||
return nonprintablesColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (parentColorAssessor != null) {
|
||||
return parentColorAssessor.getPositionTextColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer getPositionBackgroundColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section, boolean inSelection) {
|
||||
if (nonprintablesBackground != null && showNonprintables && section == BasicCodeAreaSection.TEXT_PREVIEW) {
|
||||
// Cache results to speed up?
|
||||
Character character = parentCharAssessor != null ? parentCharAssessor.getPreviewCharacter(rowDataPosition, byteOnRow, charOnRow, section) : null;
|
||||
if (character != null && nonprintableCharactersMapping.containsKey(character)) {
|
||||
return nonprintablesBackground;
|
||||
}
|
||||
}
|
||||
|
||||
if (parentColorAssessor != null) {
|
||||
return parentColorAssessor.getPositionBackgroundColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public char getPreviewCharacter(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section) {
|
||||
Character character = parentCharAssessor != null ? parentCharAssessor.getPreviewCharacter(rowDataPosition, byteOnRow, charOnRow, section) : null;
|
||||
if (showNonprintables && section == BasicCodeAreaSection.TEXT_PREVIEW && character != null) {
|
||||
Character altChar = nonprintableCharactersMapping.get(character);
|
||||
return altChar == null ? character : altChar;
|
||||
}
|
||||
|
||||
return character == null ? ' ' : character;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public char getPreviewCursorCharacter(long rowDataPosition, int byteOnRow, int charOnRow, byte[] cursorData, int cursorDataLength, CodeAreaSection section) {
|
||||
Character character = parentCharAssessor != null ? parentCharAssessor.getPreviewCursorCharacter(rowDataPosition, byteOnRow, charOnRow, cursorData, cursorDataLength, section) : null;
|
||||
if (showNonprintables && section == BasicCodeAreaSection.TEXT_PREVIEW && character != null) {
|
||||
Character altChar = nonprintableCharactersMapping.get(character);
|
||||
return altChar == null ? character : altChar;
|
||||
}
|
||||
|
||||
return character == null ? ' ' : character;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Optional<CodeAreaCharAssessor> getParentCharAssessor() {
|
||||
return Optional.ofNullable(parentCharAssessor);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Optional<CodeAreaColorAssessor> getParentColorAssessor() {
|
||||
return Optional.ofNullable(parentColorAssessor);
|
||||
}
|
||||
|
||||
private void buildNonprintableCharactersMapping() {
|
||||
nonprintableCharactersMapping = new HashMap<>();
|
||||
// Unicode control characters, might not be supported by font
|
||||
for (int i = 0; i < 32; i++) {
|
||||
nonprintableCharactersMapping.put((char) i, Character.toChars(9216 + i)[0]);
|
||||
}
|
||||
// Space -> Middle Dot
|
||||
nonprintableCharactersMapping.put(' ', Character.toChars(183)[0]);
|
||||
// Tab -> Right-Pointing Double Angle Quotation Mark
|
||||
nonprintableCharactersMapping.put('\t', Character.toChars(187)[0]);
|
||||
// Line Feed -> Currency Sign
|
||||
nonprintableCharactersMapping.put('\r', Character.toChars(164)[0]);
|
||||
// Carriage Return -> Pilcrow Sign
|
||||
nonprintableCharactersMapping.put('\n', Character.toChars(182)[0]);
|
||||
// Ideographic Space -> Degree Sign
|
||||
nonprintableCharactersMapping.put(Character.toChars(127)[0], Character.toChars(176)[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.highlight.android;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.basic.BasicCodeAreaSection;
|
||||
import org.exbin.bined.CodeAreaSection;
|
||||
import org.exbin.bined.highlight.android.color.CodeAreaMatchColorType;
|
||||
import org.exbin.bined.android.CodeAreaPaintState;
|
||||
import org.exbin.bined.android.CodeAreaColorAssessor;
|
||||
import org.exbin.bined.android.basic.color.CodeAreaColorsProfile;
|
||||
|
||||
/**
|
||||
* Code area search matches highlighting.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class SearchCodeAreaColorAssessor implements CodeAreaColorAssessor {
|
||||
|
||||
private final CodeAreaColorAssessor parentAssessor;
|
||||
|
||||
/**
|
||||
* Matches must be ordered by position.
|
||||
*/
|
||||
private final List<SearchMatch> matches = new ArrayList<>();
|
||||
private int currentMatchIndex = -1;
|
||||
private int matchIndex = 0;
|
||||
private long matchPosition = -1;
|
||||
|
||||
@Nullable
|
||||
private Integer foundMatchesColor;
|
||||
@Nullable
|
||||
private Integer foundMatchesBackground;
|
||||
@Nullable
|
||||
private Integer currentMatchColor;
|
||||
@Nullable
|
||||
private Integer currentMatchBackground;
|
||||
private int charactersPerRow = 1;
|
||||
|
||||
public SearchCodeAreaColorAssessor(@Nullable CodeAreaColorAssessor parentAssessor) {
|
||||
this.parentAssessor = parentAssessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPaint(CodeAreaPaintState codeAreaPaintState) {
|
||||
matchIndex = 0;
|
||||
charactersPerRow = codeAreaPaintState.getCharactersPerRow();
|
||||
CodeAreaColorsProfile colorsProfile = codeAreaPaintState.getColorsProfile();
|
||||
|
||||
foundMatchesColor = colorsProfile.getColor(CodeAreaMatchColorType.MATCH_COLOR);
|
||||
foundMatchesBackground = colorsProfile.getColor(CodeAreaMatchColorType.MATCH_BACKGROUND);
|
||||
if (foundMatchesBackground == null) {
|
||||
foundMatchesBackground = Color.rgb(180, 255, 180);
|
||||
}
|
||||
|
||||
currentMatchColor = colorsProfile.getColor(CodeAreaMatchColorType.CURRENT_MATCH_COLOR);
|
||||
currentMatchBackground = colorsProfile.getColor(CodeAreaMatchColorType.CURRENT_MATCH_BACKGROUND);
|
||||
if (currentMatchBackground == null) {
|
||||
currentMatchBackground = Color.rgb(255, 210, 180);
|
||||
}
|
||||
|
||||
if (parentAssessor != null) {
|
||||
parentAssessor.startPaint(codeAreaPaintState);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer getPositionTextColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section, boolean inSelection) {
|
||||
if ((currentMatchColor != null || foundMatchesColor != null) && !matches.isEmpty() && charOnRow < charactersPerRow - 1) {
|
||||
long dataPosition = rowDataPosition + byteOnRow;
|
||||
if (currentMatchIndex >= 0) {
|
||||
SearchMatch currentMatch = matches.get(currentMatchIndex);
|
||||
if (currentMatchColor != null && dataPosition >= currentMatch.position && dataPosition < currentMatch.position + currentMatch.length
|
||||
&& (section == BasicCodeAreaSection.TEXT_PREVIEW || charOnRow != ((currentMatch.position + currentMatch.length) - rowDataPosition) * charactersPerRow - 1)) {
|
||||
return currentMatchColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchPosition < rowDataPosition) {
|
||||
matchIndex = 0;
|
||||
}
|
||||
int lineMatchIndex = matchIndex;
|
||||
while (lineMatchIndex < matches.size()) {
|
||||
SearchMatch match = matches.get(lineMatchIndex);
|
||||
if (dataPosition >= match.position && dataPosition < match.position + match.length
|
||||
&& (section == BasicCodeAreaSection.TEXT_PREVIEW || charOnRow != ((match.position + match.length) - rowDataPosition) * charactersPerRow - 1)) {
|
||||
if (byteOnRow == 0) {
|
||||
matchIndex = lineMatchIndex;
|
||||
matchPosition = match.position;
|
||||
}
|
||||
if (foundMatchesColor != null) {
|
||||
return foundMatchesColor;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (match.position > dataPosition) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (byteOnRow == 0) {
|
||||
matchIndex = lineMatchIndex;
|
||||
matchPosition = match.position;
|
||||
}
|
||||
lineMatchIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (parentAssessor != null) {
|
||||
return parentAssessor.getPositionTextColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer getPositionBackgroundColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section, boolean inSelection) {
|
||||
if (!matches.isEmpty() && charOnRow < charactersPerRow - 1) {
|
||||
long dataPosition = rowDataPosition + byteOnRow;
|
||||
if (currentMatchIndex >= 0) {
|
||||
SearchMatch currentMatch = matches.get(currentMatchIndex);
|
||||
if (dataPosition >= currentMatch.position && dataPosition < currentMatch.position + currentMatch.length
|
||||
&& (section == BasicCodeAreaSection.TEXT_PREVIEW || charOnRow != ((currentMatch.position + currentMatch.length) - rowDataPosition) * charactersPerRow - 1)) {
|
||||
return currentMatchBackground;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchPosition < rowDataPosition) {
|
||||
matchIndex = 0;
|
||||
}
|
||||
int lineMatchIndex = matchIndex;
|
||||
while (lineMatchIndex < matches.size()) {
|
||||
SearchMatch match = matches.get(lineMatchIndex);
|
||||
if (dataPosition >= match.position && dataPosition < match.position + match.length
|
||||
&& (section == BasicCodeAreaSection.TEXT_PREVIEW || charOnRow != ((match.position + match.length) - rowDataPosition) * charactersPerRow - 1)) {
|
||||
if (byteOnRow == 0) {
|
||||
matchIndex = lineMatchIndex;
|
||||
matchPosition = match.position;
|
||||
}
|
||||
return foundMatchesBackground;
|
||||
}
|
||||
|
||||
if (match.position > dataPosition) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (byteOnRow == 0) {
|
||||
matchIndex = lineMatchIndex;
|
||||
matchPosition = match.position;
|
||||
}
|
||||
lineMatchIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (parentAssessor != null) {
|
||||
return parentAssessor.getPositionBackgroundColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CodeAreaColorAssessor> getParentColorAssessor() {
|
||||
return Optional.ofNullable(parentAssessor);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public List<SearchMatch> getMatches() {
|
||||
return matches;
|
||||
}
|
||||
|
||||
public void setMatches(List<SearchMatch> matches) {
|
||||
this.matches.clear();
|
||||
this.matches.addAll(matches);
|
||||
currentMatchIndex = -1;
|
||||
}
|
||||
|
||||
public void clearMatches() {
|
||||
this.matches.clear();
|
||||
currentMatchIndex = -1;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SearchMatch getCurrentMatch() {
|
||||
if (currentMatchIndex >= 0) {
|
||||
return matches.get(currentMatchIndex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getCurrentMatchIndex() {
|
||||
return currentMatchIndex;
|
||||
}
|
||||
|
||||
public void setCurrentMatchIndex(int currentMatchIndex) {
|
||||
this.currentMatchIndex = currentMatchIndex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.highlight.android;
|
||||
|
||||
/**
|
||||
* Simple POJO class for search match.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
public class SearchMatch {
|
||||
|
||||
long position;
|
||||
long length;
|
||||
|
||||
public SearchMatch() {
|
||||
}
|
||||
|
||||
public SearchMatch(long position, long length) {
|
||||
this.position = position;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public long getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(long position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public void setLength(long length) {
|
||||
this.length = length;
|
||||
}
|
||||
}
|
||||
+4
-5
@@ -19,7 +19,6 @@ import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.color.CodeAreaBasicColors;
|
||||
import org.exbin.bined.color.CodeAreaColorGroup;
|
||||
import org.exbin.bined.color.CodeAreaColorType;
|
||||
|
||||
@@ -31,10 +30,10 @@ import org.exbin.bined.color.CodeAreaColorType;
|
||||
@ParametersAreNonnullByDefault
|
||||
public enum CodeAreaColorizationColorType implements CodeAreaColorType {
|
||||
|
||||
CONTROL_CODES_COLOR(CodeAreaBasicColors.TEXT_COLOR.getId(), ColorizationCodeAreaColorsGroup.COLORIZATION),
|
||||
CONTROL_CODES_BACKGROUND(CodeAreaBasicColors.TEXT_BACKGROUND.getId(), ColorizationCodeAreaColorsGroup.COLORIZATION),
|
||||
UPPER_CODES_COLOR(CodeAreaBasicColors.TEXT_COLOR.getId(), ColorizationCodeAreaColorsGroup.COLORIZATION),
|
||||
UPPER_CODES_BACKGROUND(CodeAreaBasicColors.TEXT_BACKGROUND.getId(), ColorizationCodeAreaColorsGroup.COLORIZATION);
|
||||
CONTROL_CODES_COLOR("controlCodesColor", ColorizationCodeAreaColorsGroup.COLORIZATION),
|
||||
CONTROL_CODES_BACKGROUND("controlCodesBackground", ColorizationCodeAreaColorsGroup.COLORIZATION),
|
||||
UPPER_CODES_COLOR("upperCodesColor", ColorizationCodeAreaColorsGroup.COLORIZATION),
|
||||
UPPER_CODES_BACKGROUND("upperCodesBackground", ColorizationCodeAreaColorsGroup.COLORIZATION);
|
||||
|
||||
@Nonnull
|
||||
private final String typeId;
|
||||
|
||||
+4
-5
@@ -19,7 +19,6 @@ import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.color.CodeAreaBasicColors;
|
||||
import org.exbin.bined.color.CodeAreaColorGroup;
|
||||
import org.exbin.bined.color.CodeAreaColorType;
|
||||
|
||||
@@ -31,10 +30,10 @@ import org.exbin.bined.color.CodeAreaColorType;
|
||||
@ParametersAreNonnullByDefault
|
||||
public enum CodeAreaMatchColorType implements CodeAreaColorType {
|
||||
|
||||
MATCH_COLOR(CodeAreaBasicColors.TEXT_COLOR.getId(), MatchCodeAreaColorsGroup.MATCHING),
|
||||
MATCH_BACKGROUND(CodeAreaBasicColors.TEXT_BACKGROUND.getId(), MatchCodeAreaColorsGroup.MATCHING),
|
||||
ACTIVE_MATCH_COLOR(CodeAreaBasicColors.TEXT_COLOR.getId(), MatchCodeAreaColorsGroup.MATCHING),
|
||||
ACTIVE_MATCH_BACKGROUND(CodeAreaBasicColors.TEXT_BACKGROUND.getId(), MatchCodeAreaColorsGroup.MATCHING);
|
||||
MATCH_COLOR("matchColor", MatchCodeAreaColorsGroup.MATCHING),
|
||||
MATCH_BACKGROUND("matchBackground", MatchCodeAreaColorsGroup.MATCHING),
|
||||
CURRENT_MATCH_COLOR("currentMatchColor", MatchCodeAreaColorsGroup.MATCHING),
|
||||
CURRENT_MATCH_BACKGROUND("currentMatchBackground", MatchCodeAreaColorsGroup.MATCHING);
|
||||
|
||||
@Nonnull
|
||||
private final String typeId;
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.highlight.android.color;
|
||||
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.color.CodeAreaBasicColors;
|
||||
import org.exbin.bined.color.CodeAreaColorGroup;
|
||||
import org.exbin.bined.color.CodeAreaColorType;
|
||||
|
||||
/**
|
||||
* Enumeration of non-printable color types.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public enum CodeAreaNonprintablesColorType implements CodeAreaColorType {
|
||||
|
||||
NONPRINTABLES_COLOR(CodeAreaBasicColors.TEXT_COLOR.getId(), NonprintableCodeAreaColorsGroup.NONPRINTABLES),
|
||||
NONPRINTABLES_BACKGROUND(CodeAreaBasicColors.TEXT_BACKGROUND.getId(), NonprintableCodeAreaColorsGroup.NONPRINTABLES);
|
||||
|
||||
@Nonnull
|
||||
private final String typeId;
|
||||
@Nullable
|
||||
private final CodeAreaColorGroup group;
|
||||
|
||||
private CodeAreaNonprintablesColorType(String typeId, @Nullable CodeAreaColorGroup group) {
|
||||
this.typeId = typeId;
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getId() {
|
||||
return typeId;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Optional<CodeAreaColorGroup> getGroup() {
|
||||
return Optional.ofNullable(group);
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.highlight.android.color;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.color.CodeAreaColorGroup;
|
||||
|
||||
/**
|
||||
* Enumeration of color groups for nonprintable colors.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public enum NonprintableCodeAreaColorsGroup implements CodeAreaColorGroup {
|
||||
|
||||
NONPRINTABLES("nonprintables");
|
||||
|
||||
@Nonnull
|
||||
private final String groupId;
|
||||
|
||||
NonprintableCodeAreaColorsGroup(String groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getId() {
|
||||
return groupId;
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ import org.exbin.bined.android.CodeAreaCore;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class CodeAreaCompoundOperation extends CodeAreaOperation implements BinaryDataCompoundOperation {
|
||||
|
||||
private final List<BinaryDataOperation> operations = new ArrayList<>();
|
||||
protected final List<BinaryDataOperation> operations = new ArrayList<>();
|
||||
|
||||
public CodeAreaCompoundOperation(CodeAreaCore codeArea) {
|
||||
super(codeArea);
|
||||
@@ -92,5 +92,4 @@ public class CodeAreaCompoundOperation extends CodeAreaOperation implements Bina
|
||||
public boolean isEmpty() {
|
||||
return operations.isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ public abstract class CodeAreaOperation implements BinaryDataUndoableOperation {
|
||||
|
||||
@Nonnull
|
||||
protected final CodeAreaCore codeArea;
|
||||
@Nonnull
|
||||
protected final DefaultCodeAreaCaretPosition backPosition = new DefaultCodeAreaCaretPosition();
|
||||
|
||||
public CodeAreaOperation(CodeAreaCore codeArea) {
|
||||
@@ -47,30 +46,11 @@ public abstract class CodeAreaOperation implements BinaryDataUndoableOperation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns type of the operation.
|
||||
*
|
||||
* @return operation type
|
||||
*/
|
||||
@Nonnull
|
||||
public abstract CodeAreaOperationType getType();
|
||||
|
||||
@Nonnull
|
||||
public CodeAreaCore getCodeArea() {
|
||||
return codeArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns caption as text.
|
||||
*
|
||||
* @return text caption
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName() {
|
||||
return getType().getName();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public CodeAreaCaretPosition getBackPosition() {
|
||||
return backPosition;
|
||||
|
||||
+78
-114
@@ -55,14 +55,13 @@ import org.exbin.bined.capability.ScrollingCapable;
|
||||
import org.exbin.bined.capability.SelectionCapable;
|
||||
import org.exbin.bined.capability.ViewModeCapable;
|
||||
import org.exbin.bined.operation.android.command.CodeAreaCommand;
|
||||
import org.exbin.bined.operation.android.command.CodeAreaCommandType;
|
||||
import org.exbin.bined.operation.android.command.CodeAreaCompoundCommand;
|
||||
import org.exbin.bined.operation.android.command.DeleteSelectionCommand;
|
||||
import org.exbin.bined.operation.android.command.EditCharDataCommand;
|
||||
import org.exbin.bined.operation.android.command.EditCodeDataCommand;
|
||||
import org.exbin.bined.operation.android.command.EditDataCommand;
|
||||
import org.exbin.bined.operation.android.command.InsertDataCommand;
|
||||
import org.exbin.bined.operation.android.command.ModifyDataCommand;
|
||||
import org.exbin.bined.operation.android.command.RemoveDataCommand;
|
||||
import org.exbin.bined.operation.undo.BinaryDataAppendableUndoRedo;
|
||||
import org.exbin.bined.operation.undo.BinaryDataUndoRedo;
|
||||
|
||||
@@ -92,15 +91,15 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
@Nonnull
|
||||
protected final CodeAreaCore codeArea;
|
||||
@Nonnull
|
||||
private EnterKeyHandlingMode enterKeyHandlingMode = EnterKeyHandlingMode.PLATFORM_SPECIFIC;
|
||||
protected EnterKeyHandlingMode enterKeyHandlingMode = EnterKeyHandlingMode.PLATFORM_SPECIFIC;
|
||||
@Nonnull
|
||||
private TabKeyHandlingMode tabKeyHandlingMode = TabKeyHandlingMode.PLATFORM_SPECIFIC;
|
||||
private final boolean codeTypeSupported;
|
||||
private final boolean viewModeSupported;
|
||||
protected TabKeyHandlingMode tabKeyHandlingMode = TabKeyHandlingMode.PLATFORM_SPECIFIC;
|
||||
protected final boolean codeTypeSupported;
|
||||
protected final boolean viewModeSupported;
|
||||
|
||||
private Context context;
|
||||
protected Context context;
|
||||
protected ClipboardManager clipboard;
|
||||
private boolean canPaste = false;
|
||||
protected boolean canPaste = false;
|
||||
private ClipDescription binedDataFlavor;
|
||||
private ClipDescription binaryDataFlavor;
|
||||
private ClipData currentClipboardData = null;
|
||||
@@ -161,7 +160,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undoSequenceBreak() {
|
||||
public void sequenceBreak() {
|
||||
editCommand = null;
|
||||
}
|
||||
|
||||
@@ -174,28 +173,28 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
switch (keyEvent.getKeyCode()) {
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT: {
|
||||
move(isSelectingMode(keyEvent), MovementDirection.LEFT);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
}
|
||||
case KeyEvent.KEYCODE_DPAD_RIGHT: {
|
||||
move(isSelectingMode(keyEvent), MovementDirection.RIGHT);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
}
|
||||
case KeyEvent.KEYCODE_DPAD_UP: {
|
||||
move(isSelectingMode(keyEvent), MovementDirection.UP);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
}
|
||||
case KeyEvent.KEYCODE_DPAD_DOWN: {
|
||||
move(isSelectingMode(keyEvent), MovementDirection.DOWN);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
@@ -206,7 +205,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
} else {
|
||||
move(isSelectingMode(keyEvent), MovementDirection.ROW_START);
|
||||
}
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
@@ -217,7 +216,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
} else {
|
||||
move(isSelectingMode(keyEvent), MovementDirection.ROW_END);
|
||||
}
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
@@ -225,7 +224,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
case KeyEvent.KEYCODE_PAGE_UP: {
|
||||
scroll(ScrollingDirection.PAGE_UP);
|
||||
move(isSelectingMode(keyEvent), MovementDirection.PAGE_UP);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
@@ -233,7 +232,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
case KeyEvent.KEYCODE_PAGE_DOWN: {
|
||||
scroll(ScrollingDirection.PAGE_DOWN);
|
||||
move(isSelectingMode(keyEvent), MovementDirection.PAGE_DOWN);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
// keyEvent.consume();
|
||||
break;
|
||||
}
|
||||
@@ -323,11 +322,14 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
EditMode editMode = ((EditModeCapable) codeArea).getEditMode();
|
||||
EditOperation editOperation = ((EditModeCapable) codeArea).getActiveOperation();
|
||||
DeleteSelectionCommand deleteSelectionCommand = null;
|
||||
long dataPosition = ((CaretCapable) codeArea).getDataPosition();
|
||||
int codeOffset = ((CaretCapable) codeArea).getCodeOffset();
|
||||
if (codeArea.hasSelection()) {
|
||||
long selectionStart = ((SelectionCapable) codeArea).getSelection().getFirst();
|
||||
dataPosition = ((SelectionCapable) codeArea).getSelection().getFirst();
|
||||
codeOffset = 0;
|
||||
deleteSelectionCommand = new DeleteSelectionCommand(codeArea);
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(selectionStart);
|
||||
undoSequenceBreak();
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(dataPosition);
|
||||
sequenceBreak();
|
||||
}
|
||||
|
||||
int value;
|
||||
@@ -348,15 +350,11 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
if (deleteSelectionCommand != null) {
|
||||
CodeAreaCompoundCommand compoundCommand = new CodeAreaCompoundCommand(codeArea);
|
||||
compoundCommand.addCommand(deleteSelectionCommand);
|
||||
long dataPosition = ((CaretCapable) codeArea).getDataPosition();
|
||||
int codeOffset = ((CaretCapable) codeArea).getCodeOffset();
|
||||
editCommand = new EditCodeDataCommand(codeArea, EditCodeDataCommand.EditCommandType.OVERWRITE, dataPosition, codeOffset, (byte) value);
|
||||
editCommand = new EditCodeDataCommand(codeArea, EditDataCommand.EditOperationType.OVERWRITE, dataPosition, codeOffset, (byte) value);
|
||||
compoundCommand.addCommand(editCommand);
|
||||
undoRedo.execute(compoundCommand);
|
||||
} else {
|
||||
long dataPosition = ((CaretCapable) codeArea).getDataPosition();
|
||||
int codeOffset = ((CaretCapable) codeArea).getCodeOffset();
|
||||
EditCodeDataCommand command = new EditCodeDataCommand(codeArea, EditCodeDataCommand.EditCommandType.OVERWRITE, dataPosition, codeOffset, (byte) value);
|
||||
EditCodeDataCommand command = new EditCodeDataCommand(codeArea, EditDataCommand.EditOperationType.OVERWRITE, dataPosition, codeOffset, (byte) value);
|
||||
if (editCommand != null && isAppendAllowed() && undoRedo instanceof BinaryDataAppendableUndoRedo) {
|
||||
if (!((BinaryDataAppendableUndoRedo) undoRedo).appendExecute(command)) {
|
||||
editCommand = command;
|
||||
@@ -370,15 +368,11 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
if (deleteSelectionCommand != null) {
|
||||
CodeAreaCompoundCommand compoundCommand = new CodeAreaCompoundCommand(codeArea);
|
||||
compoundCommand.addCommand(deleteSelectionCommand);
|
||||
long dataPosition = ((CaretCapable) codeArea).getDataPosition();
|
||||
int codeOffset = ((CaretCapable) codeArea).getCodeOffset();
|
||||
editCommand = new EditCodeDataCommand(codeArea, EditCharDataCommand.EditCommandType.INSERT, dataPosition, codeOffset, (byte) value);
|
||||
editCommand = new EditCodeDataCommand(codeArea, EditDataCommand.EditOperationType.INSERT, dataPosition, codeOffset, (byte) value);
|
||||
compoundCommand.addCommand(editCommand);
|
||||
undoRedo.execute(compoundCommand);
|
||||
} else {
|
||||
long dataPosition = ((CaretCapable) codeArea).getDataPosition();
|
||||
int codeOffset = ((CaretCapable) codeArea).getCodeOffset();
|
||||
EditCodeDataCommand command = new EditCodeDataCommand(codeArea, EditCharDataCommand.EditCommandType.INSERT, dataPosition, codeOffset, (byte) value);
|
||||
EditCodeDataCommand command = new EditCodeDataCommand(codeArea, EditDataCommand.EditOperationType.INSERT, dataPosition, codeOffset, (byte) value);
|
||||
if (editCommand != null && isAppendAllowed() && undoRedo instanceof BinaryDataAppendableUndoRedo) {
|
||||
if (!((BinaryDataAppendableUndoRedo) undoRedo).appendExecute(command)) {
|
||||
editCommand = command;
|
||||
@@ -403,23 +397,25 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
// if (editCommand != null && editCommand.wasReverted()) {
|
||||
// editCommand = null;
|
||||
// }
|
||||
|
||||
long dataPosition = ((CaretCapable) codeArea).getDataPosition();
|
||||
DeleteSelectionCommand deleteCommand = null;
|
||||
if (codeArea.hasSelection()) {
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
dataPosition = ((SelectionCapable) codeArea).getSelection().getFirst();
|
||||
deleteCommand = new DeleteSelectionCommand(codeArea);
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(dataPosition);
|
||||
}
|
||||
|
||||
if (editMode == EditMode.EXPANDING && editOperation == EditOperation.OVERWRITE) {
|
||||
if (deleteCommand != null) {
|
||||
CodeAreaCompoundCommand compoundCommand = new CodeAreaCompoundCommand(codeArea);
|
||||
compoundCommand.addCommand(deleteCommand);
|
||||
long dataPosition = ((CaretCapable) codeArea).getDataPosition();
|
||||
editCommand = new EditCharDataCommand(codeArea, EditCodeDataCommand.EditCommandType.OVERWRITE, dataPosition, keyChar);
|
||||
editCommand = new EditCharDataCommand(codeArea, EditDataCommand.EditOperationType.OVERWRITE, dataPosition, keyChar);
|
||||
compoundCommand.addCommand(editCommand);
|
||||
undoRedo.execute(compoundCommand);
|
||||
} else {
|
||||
long dataPosition = ((CaretCapable) codeArea).getDataPosition();
|
||||
EditCharDataCommand command = new EditCharDataCommand(codeArea, EditCodeDataCommand.EditCommandType.OVERWRITE, dataPosition, keyChar);
|
||||
EditCharDataCommand command = new EditCharDataCommand(codeArea, EditDataCommand.EditOperationType.OVERWRITE, dataPosition, keyChar);
|
||||
if (editCommand != null && isAppendAllowed() && undoRedo instanceof BinaryDataAppendableUndoRedo) {
|
||||
if (!((BinaryDataAppendableUndoRedo) undoRedo).appendExecute(command)) {
|
||||
editCommand = command;
|
||||
@@ -433,13 +429,11 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
if (deleteCommand != null) {
|
||||
CodeAreaCompoundCommand compoundCommand = new CodeAreaCompoundCommand(codeArea);
|
||||
compoundCommand.addCommand(deleteCommand);
|
||||
long dataPosition = ((CaretCapable) codeArea).getDataPosition();
|
||||
editCommand = new EditCharDataCommand(codeArea, EditCodeDataCommand.EditCommandType.INSERT, dataPosition, keyChar);
|
||||
editCommand = new EditCharDataCommand(codeArea, EditDataCommand.EditOperationType.INSERT, dataPosition, keyChar);
|
||||
compoundCommand.addCommand(editCommand);
|
||||
undoRedo.execute(compoundCommand);
|
||||
} else {
|
||||
long dataPosition = ((CaretCapable) codeArea).getDataPosition();
|
||||
EditCharDataCommand command = new EditCharDataCommand(codeArea, EditCodeDataCommand.EditCommandType.INSERT, dataPosition, keyChar);
|
||||
EditCharDataCommand command = new EditCharDataCommand(codeArea, EditDataCommand.EditOperationType.INSERT, dataPosition, keyChar);
|
||||
if (editCommand != null && isAppendAllowed() && undoRedo instanceof BinaryDataAppendableUndoRedo) {
|
||||
if (!((BinaryDataAppendableUndoRedo) undoRedo).appendExecute(command)) {
|
||||
editCommand = command;
|
||||
@@ -462,8 +456,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
CodeAreaSection section = ((CaretCapable) codeArea).getActiveSection();
|
||||
if (section == BasicCodeAreaSection.TEXT_PREVIEW) {
|
||||
if (((CaretCapable) codeArea).getActiveSection() == BasicCodeAreaSection.TEXT_PREVIEW) {
|
||||
String sequence = enterKeyHandlingMode.getSequence();
|
||||
if (!sequence.isEmpty()) {
|
||||
pressedCharInPreview(sequence.charAt(0));
|
||||
@@ -487,7 +480,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
if (tabKeyHandlingMode == TabKeyHandlingMode.PLATFORM_SPECIFIC || tabKeyHandlingMode == TabKeyHandlingMode.CYCLE_TO_NEXT_SECTION || tabKeyHandlingMode == TabKeyHandlingMode.CYCLE_TO_PREVIOUS_SECTION) {
|
||||
if (viewModeSupported && ((ViewModeCapable) codeArea).getViewMode() == CodeAreaViewMode.DUAL) {
|
||||
move(selectingMode, MovementDirection.SWITCH_SECTION);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
revealCursor();
|
||||
}
|
||||
} else if (((CaretCapable) codeArea).getActiveSection() == BasicCodeAreaSection.TEXT_PREVIEW) {
|
||||
@@ -521,7 +514,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
if (codeArea.hasSelection()) {
|
||||
DeleteSelectionCommand deleteSelectionCommand = new DeleteSelectionCommand(codeArea);
|
||||
undoRedo.execute(deleteSelectionCommand);
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
codeArea.notifyDataChanged();
|
||||
} else {
|
||||
// if (editCommand != null && editCommand.wasReverted()) {
|
||||
@@ -530,8 +523,13 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
|
||||
CodeAreaSection section = ((CaretCapable) codeArea).getActiveSection();
|
||||
long dataPosition = ((CaretCapable) codeArea).getDataPosition();
|
||||
if ((DELETE_CHAR == keyChar && dataPosition >= codeArea.getDataSize())
|
||||
|| (DELETE_CHAR != keyChar && (dataPosition == 0 || dataPosition > codeArea.getDataSize()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (section == BasicCodeAreaSection.CODE_MATRIX) {
|
||||
EditCodeDataCommand command = new EditCodeDataCommand(codeArea, EditCodeDataCommand.EditCommandType.DELETE, dataPosition, 0, (byte) keyChar);
|
||||
EditCodeDataCommand command = new EditCodeDataCommand(codeArea, EditDataCommand.EditOperationType.DELETE, dataPosition, 0, (byte) keyChar);
|
||||
if (editCommand != null && isAppendAllowed() && undoRedo instanceof BinaryDataAppendableUndoRedo) {
|
||||
if (!((BinaryDataAppendableUndoRedo) undoRedo).appendExecute(command)) {
|
||||
editCommand = command;
|
||||
@@ -541,7 +539,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
undoRedo.execute(editCommand);
|
||||
}
|
||||
} else {
|
||||
EditCharDataCommand command = new EditCharDataCommand(codeArea, EditCharDataCommand.EditCommandType.DELETE, dataPosition, keyChar);
|
||||
EditCharDataCommand command = new EditCharDataCommand(codeArea, EditDataCommand.EditOperationType.DELETE, dataPosition, keyChar);
|
||||
if (editCommand != null && isAppendAllowed() && undoRedo instanceof BinaryDataAppendableUndoRedo) {
|
||||
if (!((BinaryDataAppendableUndoRedo) undoRedo).appendExecute(command)) {
|
||||
editCommand = command;
|
||||
@@ -562,7 +560,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
}
|
||||
|
||||
undoRedo.execute(new DeleteSelectionCommand(codeArea));
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
codeArea.notifyDataChanged();
|
||||
}
|
||||
|
||||
@@ -629,7 +627,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
copy();
|
||||
if (editMode == EditMode.EXPANDING) {
|
||||
undoRedo.execute(new DeleteSelectionCommand(codeArea));
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
codeArea.notifyDataChanged();
|
||||
}
|
||||
}
|
||||
@@ -680,7 +678,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
}
|
||||
}
|
||||
} catch (IllegalStateException ex) {
|
||||
Logger.getLogger(CodeAreaCommandHandler.class.getName()).log(Level.SEVERE, null, ex);
|
||||
Logger.getLogger(CodeAreaOperationCommandHandler.class.getName()).log(Level.SEVERE, null, ex);
|
||||
// Clipboard not available - ignore
|
||||
}
|
||||
}
|
||||
@@ -690,7 +688,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
if (codeArea.hasSelection()) {
|
||||
deleteSelectionCommand = new DeleteSelectionCommand(codeArea);
|
||||
deleteSelectionCommand.execute();
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
}
|
||||
|
||||
EditMode editMode = ((EditModeCapable) codeArea).getEditMode();
|
||||
@@ -701,22 +699,33 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
CodeAreaCommand modifyCommand = null;
|
||||
long clipDataSize = pastedData.getDataSize();
|
||||
long insertionPosition = dataPosition;
|
||||
if ((editMode == EditMode.EXPANDING && editOperation == EditOperation.OVERWRITE) || editMode == EditMode.INPLACE) {
|
||||
BinaryData modifiedData;
|
||||
long replacedPartSize = clipDataSize;
|
||||
if (insertionPosition + replacedPartSize > dataSize) {
|
||||
replacedPartSize = dataSize - insertionPosition;
|
||||
modifiedData = pastedData.copy(0, replacedPartSize);
|
||||
} else {
|
||||
modifiedData = pastedData.copy();
|
||||
if (editMode == EditMode.INPLACE) {
|
||||
long toReplace = clipDataSize;
|
||||
if (dataPosition + toReplace > codeArea.getDataSize()) {
|
||||
toReplace = codeArea.getDataSize() - dataPosition;
|
||||
}
|
||||
if (replacedPartSize > 0) {
|
||||
modifyCommand = new ModifyDataCommand(codeArea, dataPosition, modifiedData);
|
||||
if (clipDataSize > replacedPartSize) {
|
||||
pastedData = pastedData.copy(replacedPartSize, clipDataSize - replacedPartSize);
|
||||
insertionPosition += replacedPartSize;
|
||||
if (toReplace > 0) {
|
||||
modifyCommand = new ModifyDataCommand(codeArea, dataPosition, pastedData.copy(0, toReplace));
|
||||
}
|
||||
pastedData = new ByteArrayData();
|
||||
} else {
|
||||
if (editMode == EditMode.EXPANDING && editOperation == EditOperation.OVERWRITE) {
|
||||
BinaryData modifiedData;
|
||||
long replacedPartSize = clipDataSize;
|
||||
if (insertionPosition + replacedPartSize > dataSize) {
|
||||
replacedPartSize = dataSize - insertionPosition;
|
||||
modifiedData = pastedData.copy(0, replacedPartSize);
|
||||
} else {
|
||||
pastedData = new ByteArrayData();
|
||||
modifiedData = pastedData.copy();
|
||||
}
|
||||
if (replacedPartSize > 0) {
|
||||
modifyCommand = new ModifyDataCommand(codeArea, dataPosition, modifiedData);
|
||||
if (clipDataSize > replacedPartSize) {
|
||||
pastedData = pastedData.copy(replacedPartSize, clipDataSize - replacedPartSize);
|
||||
insertionPosition += replacedPartSize;
|
||||
} else {
|
||||
pastedData = new ByteArrayData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -733,7 +742,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
|
||||
undoRedo.execute(pasteCommand);
|
||||
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
codeArea.notifyDataChanged();
|
||||
revealCursor();
|
||||
clearSelection();
|
||||
@@ -824,14 +833,14 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
}
|
||||
undoRedo.execute(pasteCommand);
|
||||
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
codeArea.notifyDataChanged();
|
||||
revealCursor();
|
||||
clearSelection();
|
||||
}
|
||||
}
|
||||
} catch (IllegalStateException ex) {
|
||||
Logger.getLogger(CodeAreaCommandHandler.class.getName()).log(Level.SEVERE, null, ex);
|
||||
Logger.getLogger(CodeAreaOperationCommandHandler.class.getName()).log(Level.SEVERE, null, ex);
|
||||
// Clipboard not available - ignore
|
||||
}
|
||||
}
|
||||
@@ -871,7 +880,7 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(caretPosition);
|
||||
updateSelection(selecting, caretPosition);
|
||||
|
||||
undoSequenceBreak();
|
||||
sequenceBreak();
|
||||
codeArea.repaint();
|
||||
}
|
||||
|
||||
@@ -929,51 +938,6 @@ public class CodeAreaOperationCommandHandler implements CodeAreaCommandHandler {
|
||||
}
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
private static class DeleteSelectionCommand extends CodeAreaCommand {
|
||||
|
||||
private final RemoveDataCommand removeCommand;
|
||||
private final long position;
|
||||
private final long size;
|
||||
|
||||
public DeleteSelectionCommand(CodeAreaCore coreArea) {
|
||||
super(coreArea);
|
||||
SelectionRange selection = ((SelectionCapable) coreArea).getSelection();
|
||||
position = selection.getFirst();
|
||||
size = selection.getLast() - position + 1;
|
||||
removeCommand = new RemoveDataCommand(coreArea, position, 0, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
removeCommand.redo();
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(position);
|
||||
clearSelection();
|
||||
((ScrollingCapable) codeArea).revealCursor();
|
||||
codeArea.notifyDataChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
removeCommand.undo();
|
||||
clearSelection();
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(position + size);
|
||||
((ScrollingCapable) codeArea).revealCursor();
|
||||
codeArea.notifyDataChanged();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CodeAreaCommandType getType() {
|
||||
return CodeAreaCommandType.DATA_REMOVED;
|
||||
}
|
||||
|
||||
private void clearSelection() {
|
||||
long dataPosition = ((CaretCapable) codeArea).getDataPosition();
|
||||
((SelectionCapable) codeArea).setSelection(dataPosition, dataPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public EnterKeyHandlingMode getEnterKeyHandlingMode() {
|
||||
return enterKeyHandlingMode;
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
*/
|
||||
package org.exbin.bined.operation.android;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.operation.BinaryDataOperationType;
|
||||
|
||||
/**
|
||||
@@ -25,44 +22,30 @@ import org.exbin.bined.operation.BinaryDataOperationType;
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public enum CodeAreaOperationType implements BinaryDataOperationType {
|
||||
|
||||
/**
|
||||
* Insert data operation.
|
||||
*/
|
||||
INSERT_DATA("Insert data"),
|
||||
INSERT_DATA,
|
||||
/**
|
||||
* Remove data operation.
|
||||
*/
|
||||
REMOVE_DATA("Remove data"),
|
||||
REMOVE_DATA,
|
||||
/**
|
||||
* Modify data operation.
|
||||
*/
|
||||
MODIFY_DATA("Modify data"),
|
||||
MODIFY_DATA,
|
||||
/**
|
||||
* Move data operation.
|
||||
*/
|
||||
MOVE_DATA("Move data"),
|
||||
MOVE_DATA,
|
||||
/**
|
||||
* Edit data operation.
|
||||
*/
|
||||
EDIT_DATA("Edit data"),
|
||||
EDIT_DATA,
|
||||
/**
|
||||
* Compound operation.
|
||||
*/
|
||||
COMPOUND("Compound operation");
|
||||
|
||||
@Nullable
|
||||
private final String name;
|
||||
|
||||
CodeAreaOperationType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
COMPOUND;
|
||||
}
|
||||
|
||||
@@ -36,14 +36,14 @@ import org.exbin.bined.operation.undo.BinaryDataUndoableCommand;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class CodeAreaUndoRedo implements BinaryDataUndoRedo, BinaryDataAppendableUndoRedo {
|
||||
|
||||
private int undoMaximumCount;
|
||||
private int undoMaximumSize;
|
||||
private int usedSize;
|
||||
private int commandPosition;
|
||||
private int syncPosition = -1;
|
||||
private final List<BinaryDataCommand> commands = new ArrayList<>();
|
||||
private final CodeAreaCore codeArea;
|
||||
private final List<BinaryDataUndoRedoChangeListener> listeners = new ArrayList<>();
|
||||
protected int undoMaximumCount;
|
||||
protected int undoMaximumSize;
|
||||
protected int usedSize;
|
||||
protected int commandPosition;
|
||||
protected int syncPosition = -1;
|
||||
protected final List<BinaryDataCommand> commands = new ArrayList<>();
|
||||
protected final CodeAreaCore codeArea;
|
||||
protected final List<BinaryDataUndoRedoChangeListener> listeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
@@ -81,13 +81,14 @@ public class CodeAreaUndoRedo implements BinaryDataUndoRedo, BinaryDataAppendabl
|
||||
if (lastCommand instanceof BinaryDataAppendableCommand) {
|
||||
if (((BinaryDataAppendableCommand) lastCommand).appendExecute(command)) {
|
||||
return true;
|
||||
} else {
|
||||
commandAdded(command);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
execute(command);
|
||||
}
|
||||
|
||||
commandAdded(command);
|
||||
execute(command);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -162,9 +163,9 @@ public class CodeAreaUndoRedo implements BinaryDataUndoRedo, BinaryDataAppendabl
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
commands.forEach((command) -> {
|
||||
for (BinaryDataCommand command : commands) {
|
||||
command.dispose();
|
||||
});
|
||||
}
|
||||
commands.clear();
|
||||
init();
|
||||
undoUpdated();
|
||||
|
||||
+4
-4
@@ -35,11 +35,11 @@ import org.exbin.bined.operation.undo.BinaryDataUndoableOperation;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class DeleteCharEditDataOperation extends CharEditDataOperation {
|
||||
|
||||
private static final char BACKSPACE_CHAR = '\b';
|
||||
private static final char DELETE_CHAR = (char) 0x7f;
|
||||
protected static final char BACKSPACE_CHAR = '\b';
|
||||
protected static final char DELETE_CHAR = (char) 0x7f;
|
||||
|
||||
private long position;
|
||||
private char value;
|
||||
protected long position;
|
||||
protected char value;
|
||||
|
||||
public DeleteCharEditDataOperation(CodeAreaCore codeArea, long startPosition, char value) {
|
||||
super(codeArea);
|
||||
|
||||
+5
-5
@@ -34,12 +34,12 @@ import org.exbin.bined.operation.undo.BinaryDataUndoableOperation;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class DeleteCodeEditDataOperation extends CodeEditDataOperation {
|
||||
|
||||
private static final char BACKSPACE_CHAR = '\b';
|
||||
private static final char DELETE_CHAR = (char) 0x7f;
|
||||
private final CodeType codeType;
|
||||
protected static final char BACKSPACE_CHAR = '\b';
|
||||
protected static final char DELETE_CHAR = (char) 0x7f;
|
||||
protected final CodeType codeType;
|
||||
|
||||
private long position;
|
||||
private byte value;
|
||||
protected long position;
|
||||
protected byte value;
|
||||
|
||||
public DeleteCodeEditDataOperation(CodeAreaCore codeArea, long startPosition, CodeType codeType, byte value) {
|
||||
super(codeArea);
|
||||
|
||||
+2
-2
@@ -36,8 +36,8 @@ import org.exbin.bined.operation.undo.BinaryDataUndoableOperation;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class InsertCharEditDataOperation extends CharEditDataOperation {
|
||||
|
||||
private final long startPosition;
|
||||
private final char value;
|
||||
protected final long startPosition;
|
||||
protected final char value;
|
||||
|
||||
public InsertCharEditDataOperation(CodeAreaCore coreArea, long startPosition, char value) {
|
||||
super(coreArea);
|
||||
|
||||
+8
-8
@@ -35,15 +35,15 @@ import org.exbin.bined.operation.undo.BinaryDataUndoableOperation;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class InsertCodeEditDataOperation extends CodeEditDataOperation {
|
||||
|
||||
private final long startPosition;
|
||||
private final int startCodeOffset;
|
||||
private boolean trailing = false;
|
||||
private EditableBinaryData trailingValue = null;
|
||||
private final CodeType codeType;
|
||||
private byte value;
|
||||
protected final long startPosition;
|
||||
protected final int startCodeOffset;
|
||||
protected boolean trailing = false;
|
||||
protected EditableBinaryData trailingValue = null;
|
||||
protected final CodeType codeType;
|
||||
protected byte value;
|
||||
|
||||
private long length;
|
||||
private int codeOffset = 0;
|
||||
protected long length;
|
||||
protected int codeOffset = 0;
|
||||
|
||||
public InsertCodeEditDataOperation(CodeAreaCore codeArea, long startPosition, int startCodeOffset, byte value) {
|
||||
super(codeArea);
|
||||
|
||||
@@ -31,9 +31,9 @@ import org.exbin.bined.operation.undo.BinaryDataUndoableOperation;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class InsertDataOperation extends CodeAreaOperation {
|
||||
|
||||
private final long position;
|
||||
private final int codeOffset;
|
||||
private final BinaryData data;
|
||||
protected final long position;
|
||||
protected final int codeOffset;
|
||||
protected final BinaryData data;
|
||||
|
||||
public InsertDataOperation(CodeAreaCore codeArea, long position, int codeOffset, BinaryData data) {
|
||||
super(codeArea);
|
||||
|
||||
@@ -30,8 +30,8 @@ import org.exbin.bined.operation.undo.BinaryDataUndoableOperation;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class ModifyDataOperation extends CodeAreaOperation {
|
||||
|
||||
private final long position;
|
||||
private final BinaryData data;
|
||||
protected final long position;
|
||||
protected final BinaryData data;
|
||||
|
||||
public ModifyDataOperation(CodeAreaCore codeArea, long position, BinaryData data) {
|
||||
super(codeArea);
|
||||
|
||||
+3
-3
@@ -37,9 +37,9 @@ import org.exbin.bined.operation.undo.BinaryDataUndoableOperation;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class OverwriteCharEditDataOperation extends CharEditDataOperation {
|
||||
|
||||
private final long startPosition;
|
||||
private long length = 0;
|
||||
private char value;
|
||||
protected final long startPosition;
|
||||
protected long length = 0;
|
||||
protected char value;
|
||||
|
||||
public OverwriteCharEditDataOperation(CodeAreaCore coreArea, long startPosition, char value) {
|
||||
super(coreArea);
|
||||
|
||||
+4
-4
@@ -34,10 +34,10 @@ import org.exbin.bined.operation.undo.BinaryDataUndoableOperation;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class OverwriteCodeEditDataOperation extends CodeEditDataOperation {
|
||||
|
||||
private final long startPosition;
|
||||
private final int codeOffset;
|
||||
private final CodeType codeType;
|
||||
private byte value;
|
||||
protected final long startPosition;
|
||||
protected final int codeOffset;
|
||||
protected final CodeType codeType;
|
||||
protected byte value;
|
||||
|
||||
public OverwriteCodeEditDataOperation(CodeAreaCore codeArea, long startPosition, int codeOffset, CodeType codeType, byte value) {
|
||||
super(codeArea);
|
||||
|
||||
@@ -31,9 +31,9 @@ import org.exbin.bined.operation.undo.BinaryDataUndoableOperation;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class RemoveDataOperation extends CodeAreaOperation {
|
||||
|
||||
private final long position;
|
||||
private final int codeOffset;
|
||||
private final long length;
|
||||
protected final long position;
|
||||
protected final int codeOffset;
|
||||
protected final long length;
|
||||
|
||||
public RemoveDataOperation(CodeAreaCore codeArea, long position, int codeOffset, long length) {
|
||||
super(codeArea);
|
||||
|
||||
@@ -34,18 +34,4 @@ public abstract class CodeAreaCommand extends BinaryDataAbstractCommand {
|
||||
public CodeAreaCommand(CodeAreaCore codeArea) {
|
||||
this.codeArea = codeArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns type of the command.
|
||||
*
|
||||
* @return command type
|
||||
*/
|
||||
@Nonnull
|
||||
public abstract CodeAreaCommandType getType();
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName() {
|
||||
return getType().getName();
|
||||
}
|
||||
}
|
||||
|
||||
+6
-21
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.exbin.bined.operation.android.command;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.operation.BinaryDataCommandType;
|
||||
|
||||
/**
|
||||
@@ -24,43 +22,30 @@ import org.exbin.bined.operation.BinaryDataCommandType;
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public enum CodeAreaCommandType implements BinaryDataCommandType {
|
||||
|
||||
/**
|
||||
* Insert data command.
|
||||
*/
|
||||
DATA_INSERTED("Data inserted"),
|
||||
DATA_INSERTED,
|
||||
/**
|
||||
* Remove data command.
|
||||
*/
|
||||
DATA_REMOVED("Data removed"),
|
||||
DATA_REMOVED,
|
||||
/**
|
||||
* Modify data command.
|
||||
*/
|
||||
DATA_MODIFIED("Data modified"),
|
||||
DATA_MODIFIED,
|
||||
/**
|
||||
* Move data command.
|
||||
*/
|
||||
DATA_MOVED("Data moved"),
|
||||
DATA_MOVED,
|
||||
/**
|
||||
* Compound command.
|
||||
*/
|
||||
COMPOUND("Compound"),
|
||||
COMPOUND,
|
||||
/**
|
||||
* Edit data command.
|
||||
*/
|
||||
DATA_EDITED("Data edited");
|
||||
|
||||
private final String name;
|
||||
|
||||
CodeAreaCommandType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
DATA_EDITED;
|
||||
}
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.operation.android.command;
|
||||
|
||||
import org.exbin.bined.SelectionRange;
|
||||
import org.exbin.bined.android.CodeAreaCore;
|
||||
import org.exbin.bined.capability.CaretCapable;
|
||||
import org.exbin.bined.capability.ScrollingCapable;
|
||||
import org.exbin.bined.capability.SelectionCapable;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
/**
|
||||
* Command for deleting data.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class DeleteSelectionCommand extends CodeAreaCommand {
|
||||
|
||||
private final RemoveDataCommand removeCommand;
|
||||
private final long position;
|
||||
private final long size;
|
||||
|
||||
public DeleteSelectionCommand(CodeAreaCore coreArea) {
|
||||
super(coreArea);
|
||||
SelectionRange selection = ((SelectionCapable) coreArea).getSelection();
|
||||
position = selection.getFirst();
|
||||
size = selection.getLast() - position + 1;
|
||||
removeCommand = new RemoveDataCommand(coreArea, position, 0, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
removeCommand.execute();
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(position);
|
||||
clearSelection();
|
||||
((ScrollingCapable) codeArea).revealCursor();
|
||||
codeArea.notifyDataChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void redo() {
|
||||
removeCommand.redo();
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(position);
|
||||
clearSelection();
|
||||
((ScrollingCapable) codeArea).revealCursor();
|
||||
codeArea.notifyDataChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
removeCommand.undo();
|
||||
clearSelection();
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(position + size);
|
||||
((ScrollingCapable) codeArea).revealCursor();
|
||||
codeArea.notifyDataChanged();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public CodeAreaCommandType getType() {
|
||||
return CodeAreaCommandType.DATA_REMOVED;
|
||||
}
|
||||
|
||||
private void clearSelection() {
|
||||
long dataPosition = ((CaretCapable) codeArea).getDataPosition();
|
||||
((SelectionCapable) codeArea).setSelection(dataPosition, dataPosition);
|
||||
}
|
||||
}
|
||||
+13
-8
@@ -37,14 +37,14 @@ import org.exbin.bined.android.CodeAreaCore;
|
||||
public class EditCharDataCommand extends EditDataCommand implements BinaryDataAppendableCommand {
|
||||
|
||||
@Nonnull
|
||||
private final EditCommandType commandType;
|
||||
protected final EditOperationType editOperationType;
|
||||
protected BinaryDataCommandPhase phase = BinaryDataCommandPhase.CREATED;
|
||||
private BinaryDataUndoableOperation activeOperation;
|
||||
protected BinaryDataUndoableOperation activeOperation;
|
||||
|
||||
public EditCharDataCommand(CodeAreaCore codeArea, EditCommandType commandType, long position, char charData) {
|
||||
public EditCharDataCommand(CodeAreaCore codeArea, EditOperationType editOperationType, long position, char charData) {
|
||||
super(codeArea);
|
||||
this.commandType = commandType;
|
||||
switch (commandType) {
|
||||
this.editOperationType = editOperationType;
|
||||
switch (editOperationType) {
|
||||
case INSERT: {
|
||||
activeOperation = new InsertCharEditDataOperation(codeArea, position, charData);
|
||||
break;
|
||||
@@ -58,7 +58,7 @@ public class EditCharDataCommand extends EditDataCommand implements BinaryDataAp
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw CodeAreaUtils.getInvalidTypeException(commandType);
|
||||
throw CodeAreaUtils.getInvalidTypeException(editOperationType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,12 @@ public class EditCharDataCommand extends EditDataCommand implements BinaryDataAp
|
||||
|
||||
@Override
|
||||
public boolean appendExecute(BinaryDataCommand command) {
|
||||
if (phase != BinaryDataCommandPhase.EXECUTED) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
command.execute();
|
||||
|
||||
if (command instanceof EditCharDataCommand && activeOperation instanceof BinaryDataAppendableOperation) {
|
||||
return ((BinaryDataAppendableOperation) activeOperation).appendOperation(((EditCharDataCommand) command).activeOperation);
|
||||
}
|
||||
@@ -116,8 +121,8 @@ public class EditCharDataCommand extends EditDataCommand implements BinaryDataAp
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public EditCommandType getCommandType() {
|
||||
return commandType;
|
||||
public EditOperationType getEditOperationType() {
|
||||
return editOperationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+12
-8
@@ -37,14 +37,14 @@ import org.exbin.bined.android.CodeAreaCore;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class EditCodeDataCommand extends EditDataCommand implements BinaryDataAppendableCommand {
|
||||
|
||||
private final EditCommandType commandType;
|
||||
protected final EditOperationType editOperationType;
|
||||
protected BinaryDataCommandPhase phase = BinaryDataCommandPhase.CREATED;
|
||||
private BinaryDataUndoableOperation activeOperation;
|
||||
protected BinaryDataUndoableOperation activeOperation;
|
||||
|
||||
public EditCodeDataCommand(CodeAreaCore codeArea, EditCommandType commandType, long position, int positionCodeOffset, byte value) {
|
||||
public EditCodeDataCommand(CodeAreaCore codeArea, EditOperationType editOperationType, long position, int positionCodeOffset, byte value) {
|
||||
super(codeArea);
|
||||
this.commandType = commandType;
|
||||
switch (commandType) {
|
||||
this.editOperationType = editOperationType;
|
||||
switch (editOperationType) {
|
||||
case INSERT: {
|
||||
activeOperation = new InsertCodeEditDataOperation(codeArea, position, positionCodeOffset, value);
|
||||
break;
|
||||
@@ -58,7 +58,7 @@ public class EditCodeDataCommand extends EditDataCommand implements BinaryDataAp
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw CodeAreaUtils.getInvalidTypeException(commandType);
|
||||
throw CodeAreaUtils.getInvalidTypeException(editOperationType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +106,10 @@ public class EditCodeDataCommand extends EditDataCommand implements BinaryDataAp
|
||||
|
||||
@Override
|
||||
public boolean appendExecute(BinaryDataCommand command) {
|
||||
if (phase != BinaryDataCommandPhase.EXECUTED) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
command.execute();
|
||||
|
||||
if (command instanceof EditCodeDataCommand && activeOperation instanceof BinaryDataAppendableOperation) {
|
||||
@@ -117,8 +121,8 @@ public class EditCodeDataCommand extends EditDataCommand implements BinaryDataAp
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public EditCommandType getCommandType() {
|
||||
return commandType;
|
||||
public EditOperationType getEditOperationType() {
|
||||
return editOperationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,9 +38,9 @@ public abstract class EditDataCommand extends CodeAreaCommand {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public abstract EditCommandType getCommandType();
|
||||
public abstract EditOperationType getEditOperationType();
|
||||
|
||||
public enum EditCommandType {
|
||||
public enum EditOperationType {
|
||||
INSERT, OVERWRITE, DELETE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ import org.exbin.bined.android.CodeAreaCore;
|
||||
@ParametersAreNonnullByDefault
|
||||
public class InsertDataCommand extends OpCodeAreaCommand {
|
||||
|
||||
private final long position;
|
||||
private final long dataLength;
|
||||
protected final long position;
|
||||
protected final long dataLength;
|
||||
|
||||
public InsertDataCommand(CodeAreaCore codeArea, long position, int codeOffset, BinaryData data) {
|
||||
super(codeArea);
|
||||
|
||||
@@ -58,7 +58,7 @@ public abstract class OpCodeAreaCommand extends CodeAreaCommand {
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
if (phase == BinaryDataCommandPhase.REVERTED) {
|
||||
if (phase != BinaryDataCommandPhase.EXECUTED) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public abstract class OpCodeAreaCommand extends CodeAreaCommand {
|
||||
|
||||
@Override
|
||||
public void redo() {
|
||||
if (phase == BinaryDataCommandPhase.EXECUTED) {
|
||||
if (phase != BinaryDataCommandPhase.REVERTED) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.framework.bined;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.CodeAreaSection;
|
||||
import org.exbin.bined.highlight.android.NonAsciiCodeAreaColorAssessor;
|
||||
import org.exbin.bined.highlight.android.NonprintablesCodeAreaAssessor;
|
||||
import org.exbin.bined.highlight.android.SearchCodeAreaColorAssessor;
|
||||
import org.exbin.bined.android.CodeAreaCharAssessor;
|
||||
import org.exbin.bined.android.CodeAreaColorAssessor;
|
||||
import org.exbin.bined.android.CodeAreaPaintState;
|
||||
|
||||
/**
|
||||
* Color assessor for binary editor with registrable modifiers.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class BinEdCodeAreaAssessor implements CodeAreaColorAssessor, CodeAreaCharAssessor {
|
||||
|
||||
private final List<PositionColorModifier> priorityColorModifiers = new ArrayList<>();
|
||||
private final List<PositionColorModifier> colorModifiers = new ArrayList<>();
|
||||
|
||||
private final CodeAreaColorAssessor parentColorAssessor;
|
||||
private final CodeAreaCharAssessor parentCharAssessor;
|
||||
|
||||
public BinEdCodeAreaAssessor(@Nullable CodeAreaColorAssessor parentColorAssessor, @Nullable CodeAreaCharAssessor parentCharAssessor) {
|
||||
NonAsciiCodeAreaColorAssessor nonAsciiCodeAreaColorAssessor = new NonAsciiCodeAreaColorAssessor(parentColorAssessor);
|
||||
NonprintablesCodeAreaAssessor nonprintablesCodeAreaAssessor = new NonprintablesCodeAreaAssessor(nonAsciiCodeAreaColorAssessor, parentCharAssessor);
|
||||
SearchCodeAreaColorAssessor searchCodeAreaColorAssessor = new SearchCodeAreaColorAssessor(nonprintablesCodeAreaAssessor);
|
||||
this.parentColorAssessor = searchCodeAreaColorAssessor;
|
||||
this.parentCharAssessor = nonprintablesCodeAreaAssessor;
|
||||
}
|
||||
|
||||
public void addColorModifier(PositionColorModifier colorModifier) {
|
||||
colorModifiers.add(colorModifier);
|
||||
}
|
||||
|
||||
public void removeColorModifier(PositionColorModifier colorModifier) {
|
||||
colorModifiers.remove(colorModifier);
|
||||
}
|
||||
|
||||
public void addPriorityColorModifier(PositionColorModifier colorModifier) {
|
||||
priorityColorModifiers.add(colorModifier);
|
||||
}
|
||||
|
||||
public void removePriorityColorModifier(PositionColorModifier colorModifier) {
|
||||
priorityColorModifiers.remove(colorModifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPaint(CodeAreaPaintState codeAreaPaintState) {
|
||||
for (PositionColorModifier colorModifier : priorityColorModifiers) {
|
||||
colorModifier.resetColors();
|
||||
}
|
||||
|
||||
for (PositionColorModifier colorModifier : colorModifiers) {
|
||||
colorModifier.resetColors();
|
||||
}
|
||||
|
||||
if (parentColorAssessor != null) {
|
||||
parentColorAssessor.startPaint(codeAreaPaintState);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer getPositionBackgroundColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section, boolean inSelection) {
|
||||
for (PositionColorModifier colorModifier : priorityColorModifiers) {
|
||||
Integer positionBackgroundColor = colorModifier.getPositionBackgroundColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
if (positionBackgroundColor != null) {
|
||||
return positionBackgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inSelection) {
|
||||
for (PositionColorModifier colorModifier : colorModifiers) {
|
||||
Integer positionBackgroundColor = colorModifier.getPositionBackgroundColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
if (positionBackgroundColor != null) {
|
||||
return positionBackgroundColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parentColorAssessor != null) {
|
||||
return parentColorAssessor.getPositionBackgroundColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
}
|
||||
|
||||
// if (color == null || inSelection) {
|
||||
// long dataPosition = rowDataPosition + byteOnRow;
|
||||
// if (dataPosition > 100 && dataPosition < 300) {
|
||||
// if (inSelection && color != null) {
|
||||
// return new Color(
|
||||
// (((int) (dataPosition * 17) % 255) + color.getRed()) / 2,
|
||||
// (((int) (dataPosition * 37) % 255) + color.getGreen()) / 2,
|
||||
// (((int) (dataPosition * 13) % 255) + color.getBlue()) / 2);
|
||||
// }
|
||||
// return new Color((int) (dataPosition * 17) % 255, (int) (dataPosition * 37) % 255, (int) (dataPosition * 13) % 255);
|
||||
// }
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer getPositionTextColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section, boolean inSelection) {
|
||||
for (PositionColorModifier colorModifier : priorityColorModifiers) {
|
||||
Integer positionTextColor = colorModifier.getPositionTextColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
if (positionTextColor != null) {
|
||||
return positionTextColor;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inSelection) {
|
||||
for (PositionColorModifier colorModifier : colorModifiers) {
|
||||
Integer positionTextColor = colorModifier.getPositionTextColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
if (positionTextColor != null) {
|
||||
return positionTextColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parentColorAssessor != null) {
|
||||
return parentColorAssessor.getPositionTextColor(rowDataPosition, byteOnRow, charOnRow, section, inSelection);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getPreviewCharacter(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section) {
|
||||
return parentCharAssessor != null ? parentCharAssessor.getPreviewCharacter(rowDataPosition, byteOnRow, charOnRow, section) : ' ';
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getPreviewCursorCharacter(long rowDataPosition, int byteOnRow, int charOnRow, byte[] cursorData, int cursorDataLength, CodeAreaSection section) {
|
||||
return parentCharAssessor != null ? parentCharAssessor.getPreviewCursorCharacter(rowDataPosition, byteOnRow, charOnRow, cursorData, cursorDataLength, section) : ' ';
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Optional<CodeAreaCharAssessor> getParentCharAssessor() {
|
||||
return Optional.ofNullable(parentCharAssessor);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Optional<CodeAreaColorAssessor> getParentColorAssessor() {
|
||||
return Optional.ofNullable(parentColorAssessor);
|
||||
}
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
public interface PositionColorModifier {
|
||||
|
||||
@Nullable
|
||||
Integer getPositionBackgroundColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section, boolean inSelection);
|
||||
|
||||
@Nullable
|
||||
Integer getPositionTextColor(long rowDataPosition, int byteOnRow, int charOnRow, CodeAreaSection section, boolean inSelection);
|
||||
|
||||
void resetColors();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
@@ -15,22 +16,35 @@
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="180dp"
|
||||
android:layout_height="160dp"
|
||||
android:contentDescription="@string/bined_logo_description"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
app:srcCompat="@drawable/app_icon"
|
||||
android:contentDescription="@string/bined_logo_description" />
|
||||
app:srcCompat="@drawable/app_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:linksClickable="true"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:text="@string/app_about"
|
||||
android:focusable="true"/>
|
||||
android:text="@string/app_about" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/contributors"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:linksClickable="true"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:text="Miroslav Hajda\nGovind S Nair (Hindi translation)"
|
||||
tools:ignore="HardcodedText" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/contentMain"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -225,7 +225,7 @@
|
||||
<TableLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="5dp">
|
||||
android:layout_marginStart="5dp">
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -88,11 +88,11 @@
|
||||
android:checked="true"
|
||||
android:title="@string/code_colorization" />
|
||||
<item
|
||||
android:id="@+id/non_printing_characters"
|
||||
android:id="@+id/non_printable_characters"
|
||||
android:checkable="true"
|
||||
android:checked="false"
|
||||
android:enabled="false"
|
||||
android:title="@string/non_printing_characters" />
|
||||
android:checked="true"
|
||||
android:enabled="true"
|
||||
android:title="@string/nonprintable_characters" />
|
||||
</menu>
|
||||
</item>
|
||||
<item
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">BinEd</string>
|
||||
<string name="app_about">Název: BinEd – binární/hexadecimální editor\nVerze: 0.2.1\nDodavatel: <a href="https://exbin.org">Projekt ExBin</a>\nLicence: <a href="https://www.apache.org/licenses/LICENSE-2.0">Licence Apache, verze 2.0</a>\nDomovská stránka: <a href="https://bined.exbin.org/android ">https://bined.exbin.org/android</a></string>
|
||||
<string name="app_about">Název: BinEd – binární/hexadecimální editor\nVerze: %1$s\nDodavatel: <a href="https://exbin.org">Projekt ExBin</a>\nLicence: <a href="https://www.apache.org/licenses/LICENSE-2.0">Licence Apache, verze 2.0</a>\nDomovská stránka: <a href="https://bined.exbin.org/android ">https://bined.exbin.org/android</a>\n\nPřispěvatelé:</string>
|
||||
<string name="bined_logo_description">Logo BinEd</string>
|
||||
|
||||
<string name="title_activity_settings">Nastavení</string>
|
||||
@@ -38,7 +38,7 @@
|
||||
<string name="hex_characters_case">Velikost hexadecimálních znaků</string>
|
||||
<string name="encoding">Kódování</string>
|
||||
<string name="code_colorization">Zbarvení kódu</string>
|
||||
<string name="non_printing_characters">Netisknutelné znaky</string>
|
||||
<string name="nonprintable_characters">Netisknutelné znaky</string>
|
||||
<string name="go_to_position">Přejít na pozici</string>
|
||||
<string name="edit_selection">Upravit výběr</string>
|
||||
<string name="insert_data">Vložit data</string>
|
||||
@@ -57,14 +57,18 @@
|
||||
<string name="application_about">O aplikaci</string>
|
||||
<string name="select_file">Vyberte soubor</string>
|
||||
<string name="save_as_file">Uložit jako soubor</string>
|
||||
<string name="file_modified">Soubor by upraven</string>
|
||||
<string name="file_modified">Soubor byl upraven</string>
|
||||
<string name="storage_permission_is_not_granted">Není uděleno oprávnění k úložišti</string>
|
||||
<string name="storage_permission_request">Je třeba povolit oprávnění úložiště</string>
|
||||
|
||||
<string name="button_close">Zavřít</string>
|
||||
<string name="button_donate">Podpořit</string>
|
||||
<string name="button_cancel">Zrušit</string>
|
||||
<string name="button_set">Nastavit</string>
|
||||
<string name="button_go_to">Přejít na</string>
|
||||
<string name="button_save">Uložit</string>
|
||||
<string name="button_discard">Zahodit</string>
|
||||
<string name="button_request">Vyžádat</string>
|
||||
|
||||
<string name="pref_header_appearance">Vzhled</string>
|
||||
<string name="pref_view_header">Zobrazit</string>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<resources>
|
||||
<string-array name="bytes_per_row_entries">
|
||||
<item>स्क्रीन भरें</item>
|
||||
<item>4 बाइट</item>
|
||||
<item>8 बाइट</item>
|
||||
<item>12 बाइट</item>
|
||||
<item>16 बाइट</item>
|
||||
<item>पसंद के अनुसार</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="view_mode_entries">
|
||||
<item>द्वैतिक</item>
|
||||
<item>कोड मैट्रिक्स</item>
|
||||
<item>पाठ पूर्वावलोकन</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="code_type_entries">
|
||||
<item>बाइनरी</item>
|
||||
<item>ऑक्टल</item>
|
||||
<item>दशमलव</item>
|
||||
<item>हैक्साडेसिमल</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="hex_chars_case_entries">
|
||||
<item>निम्न वर्ण</item>
|
||||
<item>उच्च वर्ण</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
@@ -0,0 +1,79 @@
|
||||
<resources>
|
||||
<string name="app_name">BinEd</string>
|
||||
<string name="app_about">नाम: BinEd - बाइनरी/हेक्स संपादक\nवर्ज़न: %1$s\nविक्रेता: <a href="https://exbin.org">ExBin प्रोजेक्ट</a>\nलाइसेंस: <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache लाइसेंस, संस्करण 2.0</a>\nमुखपृष्ठ: <a href="https://bined.exbin.org/android">https://bined.exbin.org/android</a>\n\nयोगदानकर्ताओं:</string>
|
||||
<string name="bined_logo_description">BinEd लोगो</string>
|
||||
|
||||
<!-- Actions & menu -->
|
||||
|
||||
<string name="title_activity_settings">सेटिंग्स</string>
|
||||
|
||||
<string name="action_new">नया</string>
|
||||
<string name="action_open">खोलें</string>
|
||||
<string name="action_save">सहेजें</string>
|
||||
<string name="action_save_as">के रूप में सहेजें</string>
|
||||
|
||||
<string name="action_settings">सेटिंग्स</string>
|
||||
<string name="action_about">के बारे में</string>
|
||||
|
||||
<string name="action_search">खोजें</string>
|
||||
<string name="action_undo">पूर्ववत करें</string>
|
||||
<string name="action_redo">फिर से करें</string>
|
||||
<string name="action_selection_start">चयन प्रारंभ</string>
|
||||
<string name="action_selection_end">चयन अंत</string>
|
||||
<string name="action_clear_selection">चयन साफ़ करें</string>
|
||||
<string name="action_cut">काटें</string>
|
||||
<string name="action_copy">कॉपी करें</string>
|
||||
<string name="action_copy_as_code">कोड के रूप में कॉपी करें</string>
|
||||
<string name="action_paste">पेस्ट करें</string>
|
||||
<string name="action_paste_from_code">कोड से पेस्ट करें</string>
|
||||
<string name="action_delete">हटाएँ</string>
|
||||
<string name="action_select_all">सभी का चयन करें</string>
|
||||
|
||||
<string name="action_exit">बाहर निकलें</string>
|
||||
|
||||
<string name="view_menu">देखे</string>
|
||||
<string name="visual_theme">दृश्य थीम</string>
|
||||
<string name="language">भाषा</string>
|
||||
<string name="view_mode">दृश्य मोड</string>
|
||||
<string name="code_type">कोड प्रकार</string>
|
||||
<string name="hex_characters_case">हेक्स वर्ण केस</string>
|
||||
<string name="encoding">कोडिंग</string>
|
||||
<string name="code_colorization">कोड रंगीकरण</string>
|
||||
<string name="nonprintable_characters">गैर-मुद्रण वर्ण</string>
|
||||
<string name="go_to_position">स्थान पर जाएँ</string>
|
||||
<string name="edit_selection">चयन संपादित करें</string>
|
||||
<string name="insert_data">डेटा डालें</string>
|
||||
<string name="convert_data">डेटा परिवर्तित करें</string>
|
||||
<string name="edit_menu">संपादित करें</string>
|
||||
<string name="font">फॉन्ट</string>
|
||||
<string name="bytes_per_row">प्रति पंक्ति बाइट्स</string>
|
||||
<string name="bytes_per_row_fill">स्क्रीन भरें</string>
|
||||
<string name="bytes_per_row_4">4 बाइट</string>
|
||||
<string name="bytes_per_row_8">8 बाइट</string>
|
||||
<string name="bytes_per_row_12">12 बाइट</string>
|
||||
<string name="bytes_per_row_16">16 बाइट</string>
|
||||
<string name="bytes_per_row_custom">पसंद के अनुसार</string>
|
||||
<string name="tools_menu">उपकरण</string>
|
||||
|
||||
<string name="application_about">ऐप के बारे में</string>
|
||||
<string name="select_file">एक फ़ाइल चुनें</string>
|
||||
<string name="save_as_file">फ़ाइल के रूप में सहेजें</string>
|
||||
<string name="file_modified">फ़ाइल को संशोधित किया गया</string>
|
||||
<string name="storage_permission_is_not_granted">स्टोरेज अनुमति नहीं दी गई</string>
|
||||
<string name="storage_permission_request">स्टोरेज अनुमतियाँ सक्षम करने की आवश्यकता है</string>
|
||||
|
||||
<string name="button_close">बंद करें</string>
|
||||
<string name="button_donate">उपहार देना</string>
|
||||
<string name="button_cancel">रद्द करें</string>
|
||||
<string name="button_set">सेट करें</string>
|
||||
<string name="button_go_to">जाएँ</string>
|
||||
<string name="button_save">सहेजें</string>
|
||||
<string name="button_discard">खारिज करें</string>
|
||||
<string name="button_request">अनुरोध करें</string>
|
||||
|
||||
<!-- Preference Titles -->
|
||||
|
||||
<string name="pref_header_appearance">दृश्यता</string>
|
||||
<string name="pref_view_header">दृश्य</string>
|
||||
|
||||
</resources>
|
||||
@@ -15,12 +15,14 @@
|
||||
<item>Default (system)</item>
|
||||
<item>English</item>
|
||||
<item>Česky</item>
|
||||
<item>हिंदी</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="language_values">
|
||||
<item>default</item>
|
||||
<item>en</item>
|
||||
<item>cs</item>
|
||||
<item>hi</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="bytes_per_row_entries">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<resources>
|
||||
<string name="app_name">BinEd</string>
|
||||
<string name="app_about">Name: BinEd - Binary/Hex Editor\nVersion: 0.2.1\nVendor: <a href="https://exbin.org">ExBin Project</a>\nLicense: <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>\nHomepage: <a href="https://bined.exbin.org/android">https://bined.exbin.org/android</a></string>
|
||||
<string name="app_about">Name: BinEd - Binary/Hex Editor\nVersion: %1$s\nVendor: <a href="https://exbin.org">ExBin Project</a>\nLicense: <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>\nHomepage: <a href="https://bined.exbin.org/android">https://bined.exbin.org/android</a>\n\nContributors:</string>
|
||||
<string name="bined_logo_description">BinEd Logo</string>
|
||||
|
||||
<!-- Actions & menu -->
|
||||
@@ -39,7 +39,7 @@
|
||||
<string name="hex_characters_case">Hex Characters Case</string>
|
||||
<string name="encoding">Encoding</string>
|
||||
<string name="code_colorization">Code Colorization</string>
|
||||
<string name="non_printing_characters">Non-printing Characters</string>
|
||||
<string name="nonprintable_characters">Nonprintable Characters</string>
|
||||
<string name="go_to_position">Go To Position</string>
|
||||
<string name="edit_selection">Edit Selection</string>
|
||||
<string name="insert_data">Insert Data</string>
|
||||
@@ -59,13 +59,17 @@
|
||||
<string name="select_file">Select a file</string>
|
||||
<string name="save_as_file">Save as file</string>
|
||||
<string name="file_modified">File was modified</string>
|
||||
<string name="storage_permission_is_not_granted">Storage permission is not granted</string>
|
||||
<string name="storage_permission_request">Need to enable storage permissions</string>
|
||||
|
||||
<string name="button_close">Close</string>
|
||||
<string name="button_donate">Donate</string>
|
||||
<string name="button_cancel">Cancel</string>
|
||||
<string name="button_set">Set</string>
|
||||
<string name="button_go_to">Go To</string>
|
||||
<string name="button_save">Save</string>
|
||||
<string name="button_discard">Discard</string>
|
||||
<string name="button_request">Request</string>
|
||||
|
||||
<!-- Preference Titles -->
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
app:title="@string/code_colorization" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
app:key="non_printing_characters"
|
||||
app:enabled="false"
|
||||
app:title="@string/non_printing_characters" />
|
||||
app:key="nonprintable_characters"
|
||||
app:title="@string/nonprintable_characters" />
|
||||
</PreferenceScreen>
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.auxiliary.binary_data.ByteArrayEditableData;
|
||||
import org.exbin.auxiliary.binary_data.EditableBinaryData;
|
||||
|
||||
/**
|
||||
* Tests for codeArea component.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class CodeAreaTest {
|
||||
|
||||
public static final String SAMPLE_FILES_PATH = "/org/exbin/bined/resources/test/";
|
||||
public static final String SAMPLE_5BYTES = SAMPLE_FILES_PATH + "5bytes.dat";
|
||||
public static final String SAMPLE_10BYTES = SAMPLE_FILES_PATH + "10bytes.dat";
|
||||
public static final String SAMPLE_ALLBYTES = SAMPLE_FILES_PATH + "allbytes.dat";
|
||||
|
||||
private CodeAreaTest() {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static EditableBinaryData getSampleData(String dataPath) {
|
||||
ByteArrayEditableData data = new ByteArrayEditableData();
|
||||
try (InputStream stream = CodeAreaTest.class.getResourceAsStream(dataPath)) {
|
||||
data.loadFromStream(stream);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(CodeAreaTest.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.auxiliary.binary_data.BinaryData;
|
||||
import org.exbin.auxiliary.binary_data.ByteArrayEditableData;
|
||||
import org.exbin.auxiliary.binary_data.EditableBinaryData;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test CodeAreaUtils class.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class CodeAreaUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testInsertHexStringIntoDataHexadecimal() {
|
||||
byte[] expectedData = new byte[33];
|
||||
for (int i = 0; i < 32; i++) {
|
||||
expectedData[i] = (byte) i;
|
||||
}
|
||||
expectedData[32] = (byte) 0xff;
|
||||
|
||||
EditableBinaryData resultData = new ByteArrayEditableData();
|
||||
CodeAreaUtils.insertHexStringIntoData("00 01 02 03 04 05 06 07 08 9 0A 0b c 0D E 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f ff", resultData, CodeType.HEXADECIMAL);
|
||||
checkResultData(expectedData, resultData);
|
||||
|
||||
resultData = new ByteArrayEditableData();
|
||||
CodeAreaUtils.insertHexStringIntoData("000102030405060708090A0b0c0D0E0f101112131415161718191a1b1c1d1e1fFf", resultData, CodeType.HEXADECIMAL);
|
||||
checkResultData(expectedData, resultData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertHexStringIntoDataDecimal() {
|
||||
byte[] expectedData = new byte[23];
|
||||
for (int i = 0; i < 20; i++) {
|
||||
expectedData[i] = (byte) i;
|
||||
}
|
||||
expectedData[20] = 100;
|
||||
expectedData[21] = (byte) 200;
|
||||
expectedData[22] = (byte) 255;
|
||||
|
||||
EditableBinaryData resultData = new ByteArrayEditableData();
|
||||
CodeAreaUtils.insertHexStringIntoData("00 01 02 03 04 05 06 07 08 9 10 11 12 13 14 15 16 17 18 19 100 200 255", resultData, CodeType.DECIMAL);
|
||||
checkResultData(expectedData, resultData);
|
||||
}
|
||||
|
||||
public static void checkResultData(byte[] expectedData, BinaryData data) {
|
||||
Assert.assertEquals(expectedData.length, data.getDataSize());
|
||||
byte[] resultData = new byte[expectedData.length];
|
||||
data.copyToArray(0, resultData, 0, expectedData.length);
|
||||
Assert.assertArrayEquals(expectedData, resultData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.auxiliary.binary_data.BinaryData;
|
||||
import org.exbin.auxiliary.binary_data.ByteArrayData;
|
||||
|
||||
/**
|
||||
* Simulation of huge binary data source.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class HugeBinaryData implements BinaryData {
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDataSize() {
|
||||
return Long.MAX_VALUE / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte(long longValue) {
|
||||
return (byte) (longValue % 0xff);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public BinaryData copy() {
|
||||
return new HugeBinaryData();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public BinaryData copy(long startFrom, long length) {
|
||||
if (length > Integer.MAX_VALUE) {
|
||||
throw new IllegalStateException("Unable to copy too huge memory segment");
|
||||
}
|
||||
byte[] dataArray = new byte[(int) length];
|
||||
copyToArray(startFrom, dataArray, 0, (int) length);
|
||||
return new ByteArrayData(dataArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyToArray(long startFrom, byte[] target, int offset, int length) {
|
||||
for (int position = 0; position < length; position++) {
|
||||
target[offset + position] = getByte(startFrom + position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveToStream(OutputStream out) throws IOException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public InputStream getDataInputStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.android.basic;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.auxiliary.binary_data.BinaryData;
|
||||
import org.exbin.bined.EditOperation;
|
||||
import org.exbin.bined.capability.CaretCapable;
|
||||
import org.exbin.auxiliary.binary_data.EditableBinaryData;
|
||||
import org.exbin.bined.CodeAreaTest;
|
||||
import org.exbin.bined.EditMode;
|
||||
import org.exbin.bined.android.CodeAreaAndroidUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.exbin.bined.capability.EditModeCapable;
|
||||
import org.exbin.bined.capability.SelectionCapable;
|
||||
import org.exbin.bined.android.CodeAreaCore;
|
||||
|
||||
/**
|
||||
* Tests clipboard actions for CodeArea command component.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class CodeAreaCommandClipboardTest extends CodeAreaComponentTest {
|
||||
|
||||
public CodeAreaCommandClipboardTest() {
|
||||
}
|
||||
/*
|
||||
@Test
|
||||
public void testDeleteAll() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
codeArea.selectAll();
|
||||
codeArea.delete();
|
||||
|
||||
Assert.assertEquals(0, codeArea.getDataSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopySelection() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
byte[] expectedData = new byte[2];
|
||||
sampleData.copyToArray(5, expectedData, 0, 2);
|
||||
|
||||
codeArea.setContentData(sampleData);
|
||||
((SelectionCapable) codeArea).setSelection(5, 7);
|
||||
codeArea.copy();
|
||||
|
||||
try {
|
||||
String text = (String) CodeAreaAndroidUtils.getClipboard().getData(DataFlavor.stringFlavor);
|
||||
|
||||
Assert.assertArrayEquals(expectedData, text.getBytes("UTF-8"));
|
||||
} catch (UnsupportedFlavorException | IOException ex) {
|
||||
Logger.getLogger(CodeAreaCommandClipboardTest.class.getName()).log(Level.SEVERE, null, ex);
|
||||
Assert.fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyPasteAllInOverwriteMode() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
codeArea.setContentData(sampleData);
|
||||
long dataSize = sampleData.getDataSize();
|
||||
codeArea.selectAll();
|
||||
codeArea.copy();
|
||||
codeArea.clearSelection();
|
||||
codeArea.paste();
|
||||
|
||||
Assert.assertEquals(dataSize, codeArea.getDataSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyPasteAllInInsertMode() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
((EditModeCapable) codeArea).setEditOperation(EditOperation.INSERT);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
codeArea.setContentData(sampleData);
|
||||
long dataSize = sampleData.getDataSize();
|
||||
codeArea.selectAll();
|
||||
codeArea.copy();
|
||||
codeArea.clearSelection();
|
||||
codeArea.paste();
|
||||
|
||||
Assert.assertEquals(dataSize * 2, codeArea.getDataSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyPasteAllInInplaceMode() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
((EditModeCapable) codeArea).setEditMode(EditMode.INPLACE);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
codeArea.setContentData(sampleData);
|
||||
long dataSize = sampleData.getDataSize();
|
||||
codeArea.selectAll();
|
||||
codeArea.copy();
|
||||
codeArea.clearSelection();
|
||||
codeArea.paste();
|
||||
|
||||
Assert.assertEquals(dataSize, codeArea.getDataSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyPasteInOverwriteAtTheEnd() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
codeArea.setContentData(sampleData);
|
||||
long dataSize = sampleData.getDataSize();
|
||||
codeArea.selectAll();
|
||||
codeArea.copy();
|
||||
codeArea.clearSelection();
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(dataSize);
|
||||
codeArea.paste();
|
||||
|
||||
Assert.assertEquals(dataSize * 2, codeArea.getDataSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyPasteInInsertAtTheEnd() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
((EditModeCapable) codeArea).setEditOperation(EditOperation.INSERT);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
codeArea.setContentData(sampleData);
|
||||
long dataSize = sampleData.getDataSize();
|
||||
codeArea.selectAll();
|
||||
codeArea.copy();
|
||||
codeArea.clearSelection();
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(dataSize);
|
||||
codeArea.paste();
|
||||
|
||||
Assert.assertEquals(dataSize * 2, codeArea.getDataSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyPasteInInplaceAtTheEnd() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
((EditModeCapable) codeArea).setEditMode(EditMode.INPLACE);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
codeArea.setContentData(sampleData);
|
||||
long dataSize = sampleData.getDataSize();
|
||||
codeArea.selectAll();
|
||||
codeArea.copy();
|
||||
codeArea.clearSelection();
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(dataSize);
|
||||
codeArea.paste();
|
||||
|
||||
Assert.assertEquals(dataSize, codeArea.getDataSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyPasteInOverwriteWithOverflow() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
int dataSize = (int) sampleData.getDataSize();
|
||||
int expectedSize = (int) (dataSize / 2 + dataSize);
|
||||
|
||||
byte[] expectedData = new byte[expectedSize];
|
||||
sampleData.copyToArray(0, expectedData, 0, dataSize / 2);
|
||||
sampleData.copyToArray(0, expectedData, dataSize / 2, dataSize);
|
||||
|
||||
codeArea.setContentData(sampleData);
|
||||
codeArea.selectAll();
|
||||
codeArea.copy();
|
||||
codeArea.clearSelection();
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(dataSize / 2);
|
||||
codeArea.paste();
|
||||
|
||||
Assert.assertEquals(expectedSize, codeArea.getDataSize());
|
||||
checkResultData(expectedData, codeArea.getContentData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyPasteInInsertWithOverflow() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
((EditModeCapable) codeArea).setEditOperation(EditOperation.INSERT);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
int dataSize = (int) sampleData.getDataSize();
|
||||
int expectedSize = dataSize * 2;
|
||||
|
||||
byte[] expectedData = new byte[expectedSize];
|
||||
sampleData.copyToArray(0, expectedData, 0, dataSize / 2);
|
||||
sampleData.copyToArray(0, expectedData, dataSize / 2, dataSize);
|
||||
sampleData.copyToArray(dataSize / 2, expectedData, dataSize + dataSize / 2, dataSize / 2);
|
||||
|
||||
codeArea.setContentData(sampleData);
|
||||
codeArea.selectAll();
|
||||
codeArea.copy();
|
||||
codeArea.clearSelection();
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(dataSize / 2);
|
||||
codeArea.paste();
|
||||
|
||||
Assert.assertEquals(expectedSize, codeArea.getDataSize());
|
||||
checkResultData(expectedData, codeArea.getContentData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyPasteInInplaceWithOverflow() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
((EditModeCapable) codeArea).setEditMode(EditMode.INPLACE);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
int dataSize = (int) sampleData.getDataSize();
|
||||
int expectedSize = dataSize;
|
||||
byte[] expectedData = new byte[expectedSize];
|
||||
sampleData.copyToArray(0, expectedData, 0, dataSize / 2);
|
||||
sampleData.copyToArray(0, expectedData, dataSize / 2, dataSize / 2);
|
||||
|
||||
codeArea.setContentData(sampleData);
|
||||
codeArea.selectAll();
|
||||
codeArea.copy();
|
||||
codeArea.clearSelection();
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(dataSize / 2);
|
||||
codeArea.paste();
|
||||
|
||||
Assert.assertEquals(expectedSize, codeArea.getDataSize());
|
||||
checkResultData(expectedData, codeArea.getContentData());
|
||||
}
|
||||
|
||||
public static void checkResultData(byte[] expectedData, BinaryData data) {
|
||||
Assert.assertEquals(expectedData.length, data.getDataSize());
|
||||
byte[] resultData = new byte[expectedData.length];
|
||||
data.copyToArray(0, resultData, 0, expectedData.length);
|
||||
Assert.assertArrayEquals(expectedData, resultData);
|
||||
} */
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.android.basic;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.auxiliary.binary_data.BinaryData;
|
||||
import org.exbin.auxiliary.binary_data.EditableBinaryData;
|
||||
import org.exbin.bined.CodeAreaCaretPosition;
|
||||
import org.exbin.bined.CodeAreaTest;
|
||||
import org.exbin.bined.EditOperation;
|
||||
import org.exbin.bined.capability.CaretCapable;
|
||||
import org.exbin.bined.capability.EditModeCapable;
|
||||
import org.exbin.bined.android.CodeAreaCore;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for CodeArea component.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class CodeAreaCommandEditTest extends CodeAreaComponentTest {
|
||||
|
||||
public CodeAreaCommandEditTest() {
|
||||
}
|
||||
/*
|
||||
@Test
|
||||
public void testOverwriteCodeBegin() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
int dataSize = (int) sampleData.getDataSize();
|
||||
int expectedSize = dataSize;
|
||||
byte[] expectedData = new byte[expectedSize];
|
||||
expectedData[0] = (byte) 0xa0;
|
||||
sampleData.copyToArray(1, expectedData, 1, dataSize - 1);
|
||||
|
||||
codeArea.setContentData(sampleData);
|
||||
|
||||
emulateKeyTyped(codeArea, KeyEvent.VK_UNDEFINED, 'a');
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(1, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(0, caretPosition.getDataPosition());
|
||||
checkResultData(expectedData, codeArea.getContentData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertCodeBegin() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
int dataSize = (int) sampleData.getDataSize();
|
||||
int expectedSize = dataSize + 1;
|
||||
byte[] expectedData = new byte[expectedSize];
|
||||
expectedData[0] = (byte) 0xa0;
|
||||
sampleData.copyToArray(0, expectedData, 1, dataSize);
|
||||
((EditModeCapable) codeArea).setEditOperation(EditOperation.INSERT);
|
||||
|
||||
codeArea.setContentData(sampleData);
|
||||
|
||||
emulateKeyTyped(codeArea, KeyEvent.VK_UNDEFINED, 'a');
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(1, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(0, caretPosition.getDataPosition());
|
||||
checkResultData(expectedData, codeArea.getContentData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverwriteCodeEnd() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
int dataSize = (int) sampleData.getDataSize();
|
||||
int expectedSize = dataSize + 1;
|
||||
byte[] expectedData = new byte[expectedSize];
|
||||
expectedData[256] = (byte) 0xa0;
|
||||
sampleData.copyToArray(0, expectedData, 0, dataSize);
|
||||
|
||||
codeArea.setContentData(sampleData);
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(256);
|
||||
|
||||
emulateKeyTyped(codeArea, KeyEvent.VK_UNDEFINED, 'a');
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(1, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(256, caretPosition.getDataPosition());
|
||||
checkResultData(expectedData, codeArea.getContentData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertCodeEnd() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
int dataSize = (int) sampleData.getDataSize();
|
||||
int expectedSize = dataSize + 1;
|
||||
byte[] expectedData = new byte[expectedSize];
|
||||
expectedData[256] = (byte) 0xa0;
|
||||
sampleData.copyToArray(0, expectedData, 0, dataSize);
|
||||
((EditModeCapable) codeArea).setEditOperation(EditOperation.INSERT);
|
||||
|
||||
codeArea.setContentData(sampleData);
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(256);
|
||||
|
||||
emulateKeyTyped(codeArea, KeyEvent.VK_UNDEFINED, 'a');
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(1, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(256, caretPosition.getDataPosition());
|
||||
checkResultData(expectedData, codeArea.getContentData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteKeyEmpty() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_UNDEFINED, KeyEvent.VK_DELETE);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(0, caretPosition.getDataPosition());
|
||||
Assert.assertEquals(0, codeArea.getDataSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteKeyBegin() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
int dataSize = (int) sampleData.getDataSize();
|
||||
int expectedSize = dataSize - 1;
|
||||
byte[] expectedData = new byte[expectedSize];
|
||||
sampleData.copyToArray(1, expectedData, 0, dataSize - 1);
|
||||
|
||||
codeArea.setContentData(sampleData);
|
||||
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_UNDEFINED, KeyEvent.VK_DELETE);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(0, caretPosition.getDataPosition());
|
||||
checkResultData(expectedData, codeArea.getContentData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteKeyEnd() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
codeArea.setContentData(sampleData);
|
||||
int dataSize = (int) sampleData.getDataSize();
|
||||
int expectedSize = dataSize;
|
||||
byte[] expectedData = new byte[expectedSize];
|
||||
sampleData.copyToArray(0, expectedData, 0, dataSize);
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(256);
|
||||
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_UNDEFINED, KeyEvent.VK_DELETE);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(256, caretPosition.getDataPosition());
|
||||
checkResultData(expectedData, codeArea.getContentData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackspaceKeyEmpty() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_UNDEFINED, KeyEvent.VK_BACK_SPACE);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(0, caretPosition.getDataPosition());
|
||||
Assert.assertEquals(0, codeArea.getDataSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackspaceKeyBegin() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
int dataSize = (int) sampleData.getDataSize();
|
||||
int expectedSize = dataSize;
|
||||
byte[] expectedData = new byte[expectedSize];
|
||||
sampleData.copyToArray(0, expectedData, 0, dataSize);
|
||||
|
||||
codeArea.setContentData(sampleData);
|
||||
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_UNDEFINED, KeyEvent.VK_BACK_SPACE);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(0, caretPosition.getDataPosition());
|
||||
checkResultData(expectedData, codeArea.getContentData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackspaceKeyEnd() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
EditableBinaryData sampleData = CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES);
|
||||
codeArea.setContentData(sampleData);
|
||||
int dataSize = (int) sampleData.getDataSize();
|
||||
int expectedSize = dataSize - 1;
|
||||
byte[] expectedData = new byte[expectedSize];
|
||||
sampleData.copyToArray(0, expectedData, 0, dataSize - 1);
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(256);
|
||||
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_UNDEFINED, KeyEvent.VK_BACK_SPACE);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(255, caretPosition.getDataPosition());
|
||||
checkResultData(expectedData, codeArea.getContentData());
|
||||
}
|
||||
|
||||
private static void emulateKeyTyped(Component component, int keyEvent, char keyChar) {
|
||||
component.dispatchEvent(new KeyEvent(component, KeyEvent.KEY_TYPED, System.currentTimeMillis(), 0, keyEvent, keyChar));
|
||||
}
|
||||
|
||||
private static void emulateKeyPressed(Component component, int keyCode, int keyEvent) {
|
||||
component.dispatchEvent(new KeyEvent(component, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), keyCode, keyEvent, ' '));
|
||||
}
|
||||
|
||||
public static void checkResultData(byte[] expectedData, BinaryData data) {
|
||||
Assert.assertEquals(expectedData.length, data.getDataSize());
|
||||
byte[] resultData = new byte[expectedData.length];
|
||||
data.copyToArray(0, resultData, 0, expectedData.length);
|
||||
Assert.assertArrayEquals(expectedData, resultData);
|
||||
} */
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.android.basic;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import org.exbin.bined.CodeAreaCaretPosition;
|
||||
import org.exbin.bined.CodeAreaTest;
|
||||
import org.exbin.bined.capability.CaretCapable;
|
||||
import org.exbin.bined.android.CodeAreaCore;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for CodeArea component.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
public class CodeAreaCommandMovementTest extends CodeAreaComponentTest {
|
||||
|
||||
public CodeAreaCommandMovementTest() {
|
||||
}
|
||||
/*
|
||||
@Test
|
||||
public void testMoveBeginLeft() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_LEFT, KeyEvent.CHAR_UNDEFINED);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(0, caretPosition.getDataPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveMiddleLeft() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(128);
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_LEFT, KeyEvent.CHAR_UNDEFINED);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(1, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(127, caretPosition.getDataPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveEndLeft() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(257);
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_LEFT, KeyEvent.CHAR_UNDEFINED);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(1, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(256, caretPosition.getDataPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveBeginRight() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_RIGHT, KeyEvent.CHAR_UNDEFINED);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(1, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(0, caretPosition.getDataPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveBeginRightTwice() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_RIGHT, KeyEvent.CHAR_UNDEFINED);
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_RIGHT, KeyEvent.CHAR_UNDEFINED);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(1, caretPosition.getDataPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveMiddleRight() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(128);
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_RIGHT, KeyEvent.CHAR_UNDEFINED);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(1, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(128, caretPosition.getDataPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveEndRight() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(257);
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_RIGHT, KeyEvent.CHAR_UNDEFINED);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(257, caretPosition.getDataPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveBeginUp() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_UP, KeyEvent.CHAR_UNDEFINED);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(0, caretPosition.getDataPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveMiddleUp() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(128);
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_UP, KeyEvent.CHAR_UNDEFINED);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(112, caretPosition.getDataPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveEndUp() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(257);
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_UP, KeyEvent.CHAR_UNDEFINED);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(241, caretPosition.getDataPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveBeginDown() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_DOWN, KeyEvent.CHAR_UNDEFINED);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(16, caretPosition.getDataPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveMiddleDown() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(128);
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_DOWN, KeyEvent.CHAR_UNDEFINED);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(144, caretPosition.getDataPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveEndDown() {
|
||||
CodeAreaCore codeArea = createCodeArea();
|
||||
JFrame frame = new JFrame();
|
||||
frame.add(codeArea);
|
||||
frame.setVisible(true);
|
||||
codeArea.setContentData(CodeAreaTest.getSampleData(CodeAreaTest.SAMPLE_ALLBYTES));
|
||||
|
||||
((CaretCapable) codeArea).setActiveCaretPosition(257);
|
||||
emulateKeyPressed(codeArea, KeyEvent.VK_DOWN, KeyEvent.CHAR_UNDEFINED);
|
||||
|
||||
CodeAreaCaretPosition caretPosition = ((CaretCapable) codeArea).getActiveCaretPosition();
|
||||
Assert.assertEquals(0, caretPosition.getCodeOffset());
|
||||
Assert.assertEquals(257, caretPosition.getDataPosition());
|
||||
}
|
||||
|
||||
private void emulateKeyPressed(Component component, int keyEvent, char keyChar) {
|
||||
component.dispatchEvent(new KeyEvent(component, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0, keyEvent, keyChar));
|
||||
component.dispatchEvent(new KeyEvent(component, KeyEvent.KEY_RELEASED, System.currentTimeMillis(), 0, keyEvent, keyChar));
|
||||
} */
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) ExBin Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.exbin.bined.android.basic;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import org.exbin.bined.android.CodeAreaCore;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Tests for CodeArea component.
|
||||
*
|
||||
* @author ExBin Project (https://exbin.org)
|
||||
*/
|
||||
public class CodeAreaComponentTest {
|
||||
|
||||
public CodeAreaComponentTest() {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public CodeAreaCore createCodeArea() {
|
||||
Context applicationContext = ApplicationProvider.getApplicationContext();
|
||||
AttributeSet attributeSet = null;
|
||||
return new CodeArea(applicationContext, attributeSet);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user