Java tutorial
/* * Copyright (c) 2017 Tran Le Duy * * 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 * * http://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 com.duy.pascal.ui.editor; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.design.widget.NavigationView; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AlertDialog; import android.text.InputType; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.CheckBox; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import com.duy.pascal.interperter.ast.CodeUnitParsingException; import com.duy.pascal.interperter.ast.codeunit.CodeUnit; import com.duy.pascal.interperter.ast.expressioncontext.ExpressionContextMixin; import com.duy.pascal.interperter.core.PascalCompilerFactory; import com.duy.pascal.interperter.declaration.program.PascalProgramDeclaration; import com.duy.pascal.interperter.exceptions.parsing.ParsingException; import com.duy.pascal.interperter.exceptions.parsing.define.MainProgramNotFoundException; import com.duy.pascal.interperter.libraries.io.IOLib; import com.duy.pascal.interperter.source.FileScriptSource; import com.duy.pascal.interperter.source.ScriptSource; import com.duy.pascal.ui.R; import com.duy.pascal.ui.autocomplete.autofix.command.AutoFixCommand; import com.duy.pascal.ui.autocomplete.autofix.dialog.ErrorAndQuickFixDialog; import com.duy.pascal.ui.autocomplete.completion.model.Description; import com.duy.pascal.ui.code.CompileManager; import com.duy.pascal.ui.code.sample.activities.DocumentActivity; import com.duy.pascal.ui.common.utils.UIUtils; import com.duy.pascal.ui.editor.view.EditorView; import com.duy.pascal.ui.file.FileManager; import com.duy.pascal.ui.file.util.FileUtils; import com.duy.pascal.ui.runnable.IProgramHandler; import com.duy.pascal.ui.setting.PascalPreferences; import com.duy.pascal.ui.structure.DialogProgramStructure; import com.duy.pascal.ui.structure.viewholder.StructureItem; import com.duy.pascal.ui.themefont.activities.ThemeFontActivity; import com.duy.pascal.ui.utils.DLog; import com.duy.pascal.ui.utils.StoreUtil; import com.duy.pascal.ui.view.console.ConsoleView; import com.flask.colorpicker.builder.ColorPickerClickListener; import com.flask.colorpicker.builder.ColorPickerDialogBuilder; import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Locale; public class EditorActivity extends BaseEditorActivity implements DrawerLayout.DrawerListener { public static final int ACTION_FILE_SELECT_CODE = 1012; public static final int ACTION_PICK_MEDIA_URL = 1013; public static final int ACTION_CREATE_SHORTCUT = 1014; private CompileManager mCompileManager; private EditorDelegate mEditorDelegate; private Dialog mDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCompileManager = new CompileManager(this); mEditorDelegate = new EditorDelegate(this, this); mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { mDrawerLayout.closeDrawers(); return mEditorDelegate.onOptionsItemSelected(item); } }); findViewById(R.id.img_tab).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { insertTabCharacter(v); } }); } @Override public boolean onOptionsItemSelected(MenuItem item) { return mEditorDelegate.onOptionsItemSelected(item); } @Override public void invalidateOptionsMenu() { super.invalidateOptionsMenu(); } private void insertTabCharacter(View v) { EditorFragment currentFragment = mPagerAdapter.getCurrentFragment(); if (currentFragment != null) { currentFragment.executeCommand(new AutoFixCommand() { @Override public void execute(EditorView editable) { editable.insert(editable.getTabCharacter()); } @NonNull @Override public CharSequence getTitle(Context context) { return "Insert tab"; } }); } } @Override public void onKeyClick(View view, String text) { EditorFragment currentFragment = getEditorFragment(); if (currentFragment != null) { currentFragment.insert(text); } } @Override public void onKeyLongClick(String text) { EditorFragment currentFragment = getEditorFragment(); if (currentFragment != null) { currentFragment.insert(text); } } @Override public boolean onCreateOptionsMenu(Menu menu) { return mEditorDelegate.onCreateOptionsMenu(menu); } /** * create dialog find and replace */ @Override public void findAndReplace() { AlertDialog.Builder builder = new AlertDialog.Builder(EditorActivity.this); builder.setView(R.layout.dialog_find_and_replace); final AlertDialog alertDialog = builder.create(); alertDialog.show(); final CheckBox ckbRegex = alertDialog.findViewById(R.id.ckb_regex); final CheckBox ckbMatch = alertDialog.findViewById(R.id.ckb_match_key); final EditText editFind = alertDialog.findViewById(R.id.txt_find); final EditText editReplace = alertDialog.findViewById(R.id.edit_replace); editFind.setText(getPreferences().getString(PascalPreferences.LAST_FIND)); alertDialog.findViewById(R.id.btn_replace).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { editorFragment.findAndReplace(editFind.getText().toString(), editReplace.getText().toString(), ckbRegex.isChecked(), ckbMatch.isChecked()); } getPreferences().put(PascalPreferences.LAST_FIND, editFind.getText().toString()); alertDialog.dismiss(); } }); alertDialog.findViewById(R.id.btn_cancel).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { alertDialog.dismiss(); } }); } @Override public void runProgram() { if (doCompile()) mCompileManager.execute(getCurrentFilePath()); } /** * replace dialog find */ public void showDialogFind() { AlertDialog.Builder builder = new AlertDialog.Builder(EditorActivity.this); builder.setView(R.layout.dialog_find); final AlertDialog alertDialog = builder.create(); alertDialog.show(); final CheckBox ckbRegex = alertDialog.findViewById(R.id.ckb_regex); final CheckBox ckbMatch = alertDialog.findViewById(R.id.ckb_match_key); final CheckBox ckbWordOnly = alertDialog.findViewById(R.id.ckb_word_only); final EditText editFind = alertDialog.findViewById(R.id.txt_find); editFind.setText(getPreferences().getString(PascalPreferences.LAST_FIND)); alertDialog.findViewById(R.id.btn_replace).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { editorFragment.find(editFind.getText().toString(), ckbRegex.isChecked(), ckbWordOnly.isChecked(), ckbMatch.isChecked()); } getPreferences().put(PascalPreferences.LAST_FIND, editFind.getText().toString()); alertDialog.dismiss(); } }); alertDialog.findViewById(R.id.btn_cancel).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { alertDialog.dismiss(); } }); } @Override public void saveFile() { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { editorFragment.saveFile(); } } @Override public void showDocumentActivity() { Intent intent = new Intent(this, DocumentActivity.class); startActivity(intent); } private void showLineError(final ParsingException e) { if (e != null) { if (e.getLineNumber() != null) { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { editorFragment.setLineError(e.getLineNumber()); } } } } public String getCode() { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { return editorFragment.getCode(); } return ""; } /** * compile code, if is error, show dialog error * invalidate keyword */ @Override public boolean doCompile() { saveFile(); String filePath = getCurrentFilePath(); if (filePath.isEmpty()) return false; try { CodeUnit codeUnit; ArrayList<ScriptSource> searchPath = new ArrayList<>(); searchPath.add(new FileScriptSource(new File(filePath))); if (getCode().trim().toLowerCase().startsWith("unit ")) { PascalCompilerFactory.makePascalLibrary(new FileScriptSource(new File(filePath)), searchPath, new ProgramHandler(filePath)); } else { codeUnit = PascalCompilerFactory.makePascalProgram(new FileScriptSource(new File(filePath)), searchPath, new ProgramHandler(filePath)); if (((PascalProgramDeclaration) codeUnit).root == null) { showErrorDialog(new MainProgramNotFoundException()); return false; } } } catch (FileNotFoundException e) { showErrorDialog(e); return false; } catch (CodeUnitParsingException e) { showErrorDialog(e.getParseException()); showLineError(e.getParseException()); return false; } catch (ParsingException e) { showErrorDialog(e); showLineError(e); return false; } catch (Exception e) { showErrorDialog(e); return false; } Toast.makeText(this, R.string.compile_ok, Toast.LENGTH_SHORT).show(); return true; } private void showErrorDialog(Exception e) { ErrorAndQuickFixDialog quickFixDialog = ErrorAndQuickFixDialog.newInstance(e); quickFixDialog.show(getSupportFragmentManager(), ErrorAndQuickFixDialog.TAG); DLog.e(e); } @Override protected void onDestroy() { if (mDialog != null && mDialog.isShowing()) { mDialog.dismiss(); } super.onDestroy(); } @Override protected void onResume() { super.onResume(); if (getPreferences().isShowListSymbol()) { mKeyList.setListener(this); mContainerSymbol.setVisibility(View.VISIBLE); } else { mContainerSymbol.setVisibility(View.GONE); } } @Override public void onSharedPreferenceChanged(@NonNull SharedPreferences sharedPreferences, @NonNull String s) { if (s.equals(getString(R.string.key_show_suggest_popup)) || s.equals(getString(R.string.key_show_line_number)) || s.equals(getString(R.string.key_pref_word_wrap))) { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { editorFragment.refreshCodeEditor(); } } else if (s.equals(getString(R.string.key_show_symbol))) { mContainerSymbol.setVisibility(getPreferences().isShowListSymbol() ? View.VISIBLE : View.GONE); } else if (s.equals(getString(R.string.key_show_suggest_popup))) { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { EditorView editor = editorFragment.getEditor(); editor.setSuggestData(new ArrayList<Description>()); } } //toggle ime/no suggest mode else if (s.equalsIgnoreCase(getString(R.string.key_ime_keyboard))) { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { EditorView editor = editorFragment.getEditor(); editorFragment.refreshCodeEditor(); } } else { super.onSharedPreferenceChanged(sharedPreferences, s); } } @Override public boolean onFileSelected(@NonNull File file) { if (FileUtils.canEdit(file)) { //save current file addNewPageEditor(file); //close drawer mDrawerLayout.closeDrawers(); return true; } return false; } @Override public void onFileLongClick(@NonNull File file) { showFileInfo(file); } /** * show dialog with file info * filePath, path, size, extension ... * * @param file - file to show info */ private void showFileInfo(File file) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(file.getName()); builder.setView(R.layout.dialog_view_file); AlertDialog dialog = builder.create(); dialog.show(); TextView txtInfo = dialog.findViewById(R.id.txt_info); txtInfo.setText(file.getPath()); EditorView editorView = dialog.findViewById(R.id.editor_view); editorView.setTextHighlighted(mFileManager.fileToString(file)); } @Override public void goToLine() { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { int lineCount = editorFragment.getEditor().getLineCount(); String hint = String.format(Locale.US, "0-%d", lineCount); UIUtils.showInputDialog(this, getString(R.string.goto_line), hint, null, InputType.TYPE_CLASS_NUMBER, new UIUtils.OnShowInputCallback() { @Override public void onConfirm(CharSequence input) { String line = input.toString(); if (!line.isEmpty()) { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { try { int lineNumber = Integer.parseInt(line); editorFragment.goToLine(lineNumber); } catch (NumberFormatException ignored) { } } } } }); } } @Override public void formatCode() { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { editorFragment.formatCode(); } } @Override public void reportBug() { String link = "https://github.com/tranleduy2000/pascalnide/issues"; Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(link)); startActivity(intent); } @Override public void undo() { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { editorFragment.undo(); } } @Override public void redo() { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { editorFragment.redo(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case ACTION_FILE_SELECT_CODE: if (resultCode == RESULT_OK) { // Get the Uri of the selected file Uri uri = data.getData(); // Get the path String path; try { path = FileManager.getPathFromUri(this, uri); mFileManager.setWorkingFilePath(path); addNewPageEditor(new File(path)); } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show(); } } break; case ACTION_PICK_MEDIA_URL: if (resultCode == RESULT_OK) { String path = data.getData().toString(); EditorFragment currentFragment = mPagerAdapter.getCurrentFragment(); if (currentFragment != null && path != null) { currentFragment.insert(path); } } break; case ACTION_CREATE_SHORTCUT: data.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); getApplicationContext().sendBroadcast(data); break; } } @Override public void onDrawerSlide(@NonNull View drawerView, float slideOffset) { } @Override public void onDrawerOpened(@NonNull View drawerView) { closeKeyBoard(); } @Override public void onDrawerClosed(@NonNull View drawerView) { if (mFabMenu.isOpened()) { mFabMenu.close(false); } } @Override public void paste() { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { editorFragment.paste(); } } @Nullable public EditorFragment getEditorFragment() { return mPagerAdapter.getCurrentFragment(); } @Override public void selectThemeFont() { startActivity(new Intent(this, ThemeFontActivity.class)); } @Override public void onDrawerStateChanged(int newState) { } @Override public void onBackPressed() { if (mDrawerLayout.isDrawerOpen(GravityCompat.START) || mDrawerLayout.isDrawerOpen(GravityCompat.END)) { mDrawerLayout.closeDrawers(); return; } if (getPreferences().getBoolean(getString(R.string.key_back_undo)) && getEditorFragment() != null) { getEditorFragment().undo(); return; } AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.exit).setMessage(R.string.exit_mgs) .setNegativeButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { EditorActivity.super.onBackPressed(); } }).setPositiveButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }).setNeutralButton(R.string.get_more_app, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { StoreUtil.moreApp(EditorActivity.this); } }); showDialog(builder.create()); } public void openDrawer(int gravity) { mDrawerLayout.openDrawer(gravity); } private String getCurrentFilePath() { EditorFragment editorFragment = mPagerAdapter.getCurrentFragment(); if (editorFragment != null) { return editorFragment.getFilePath(); } return ""; } public void showProgramStructure() { try { String filePath = getCurrentFilePath(); PascalProgramDeclaration pascalProgram = PascalCompilerFactory.makePascalProgram( new FileScriptSource(new File(filePath)), new ArrayList<ScriptSource>(), null); if (pascalProgram.root == null) { showErrorDialog(new MainProgramNotFoundException()); } ExpressionContextMixin program = pascalProgram.getProgram(); StructureItem node = null; // node = getNode(program, pascalProgram.getProgramName(), StructureType.TYPE_PROGRAM, 0); DialogProgramStructure dialog = DialogProgramStructure.newInstance(node); dialog.show(getSupportFragmentManager(), DialogProgramStructure.TAG); } catch (Exception e) { Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show(); } } public void startDebug() { if (doCompile()) mCompileManager.debug(getCurrentFilePath()); } public void insertColor() { ColorPickerDialogBuilder.with(this) .setPositiveButton(getString(R.string.select), new ColorPickerClickListener() { @Override public void onClick(DialogInterface d, int lastSelectedColor, Integer[] allColors) { EditorFragment currentFragment = mPagerAdapter.getCurrentFragment(); if (currentFragment != null) { currentFragment.insert(String.valueOf(lastSelectedColor)); Toast.makeText(EditorActivity.this, getString(R.string.inserted_color) + lastSelectedColor, Toast.LENGTH_SHORT) .show(); } } }).setNegativeButton(R.string.close, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }).build().show(); } public void executeCommand(AutoFixCommand command) { EditorFragment currentFragment = mPagerAdapter.getCurrentFragment(); if (currentFragment != null) { currentFragment.executeCommand(command); } } private class ProgramHandler implements IProgramHandler { private String programPath; ProgramHandler(String programPath) { this.programPath = programPath; } @Override public String getCurrentDirectory() { return new File(programPath).getParent(); } @Override public Context getApplicationContext() { return EditorActivity.this.getApplicationContext(); } @Override public Activity getActivity() { return EditorActivity.this; } @Override public void startInput(IOLib lock) { } @Override public void print(CharSequence charSequence) { } @Nullable @Override public ConsoleView getConsoleView() { return null; } @Override public void println(CharSequence charSequence) { } @Override public char getKeyBuffer() { return 0; } @Override public boolean keyPressed() { return false; } @Override public void clearConsole() { } } }