package org.geogebra.common.gui.view.spreadsheet;
import java.util.ArrayList;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoElementSpreadsheet;
import org.geogebra.common.main.App;
import org.geogebra.common.main.Feature;
import org.geogebra.common.main.Localization;
import org.geogebra.common.main.OptionType;
import org.geogebra.common.plugin.EventType;
/**
* Superclass that creates a context menu for spreadsheet cells, rows and
* columns. GUI methods must be implemented by subclasses.
*
* @author G. Sturr
*
*/
public class SpreadsheetContextMenu {
/** application */
protected App app;
/** spreadsheet table */
protected MyTable table = null;
private ArrayList<GeoElement> geos;
private CellRangeProcessor cp;
private ArrayList<CellRange> selectedCellRanges;
private int selectionType;
/** minimum selected row */
private int row1 = -1;
/** maximum selected row */
private int row2 = -1;
/** minimum selected column */
private int column1 = -1;
/** maximum selected column */
private int column2 = -1;
private Localization loc;
@SuppressWarnings("javadoc")
public enum MenuCommand {
ShowObject, ShowLabel, HideLabel,
RecordToSpreadsheet, DontRecordToSpreadsheet,
Copy, Paste, Duplicate, Cut, Delete, DeleteObjects,
InsertLeft, InsertRight, InsertAbove, InsertBelow,
DeleteRow, DeleteRows, DeleteColumn, DeleteColumns,
List, ListOfPoints, Matrix, Table, PolyLine, OperationTable,
ImportDataFile,
SpreadsheetOptions, Properties;
}
/**
* Constructor
*
* @param table
* spreadsheet table
*/
public SpreadsheetContextMenu(MyTable table) {
this.table = table;
updateFields();
createGUI();
}
/**
* Update private fields.
*/
protected void updateFields() {
app = table.getApplication();
this.loc = app.getLocalization();
cp = table.getCellRangeProcessor();
column1 = table.getSelectedCellRanges().get(0).getMinColumn();
column2 = table.getSelectedCellRanges().get(0).getMaxColumn();
row1 = table.getSelectedCellRanges().get(0).getMinRow();
row2 = table.getSelectedCellRanges().get(0).getMaxRow();
selectionType = table.getSelectionType();
selectedCellRanges = table.getSelectedCellRanges();
geos = app.getSelectionManager().getSelectedGeos();
}
// ===============================================
// Menu
// ===============================================
protected void addCut() {
String cmdString = MenuCommand.Cut.toString();
addMenuItem(cmdString, loc.getMenu(cmdString), !isEmptySelection());
}
protected void addCopy() {
String cmdString = MenuCommand.Copy.toString();
addMenuItem(cmdString, loc.getMenu(cmdString), !isEmptySelection());
}
protected void addPaste() {
String cmdString = MenuCommand.Paste.toString();
addMenuItem(cmdString, loc.getMenu(cmdString), true);
}
protected void addDelete() {
// TODO use "DeleteObjects" as text ?
String cmdString = (geos != null && geos.size() > 1)
? MenuCommand.DeleteObjects.toString()
: MenuCommand.Delete.toString();
addMenuItem(cmdString, loc.getMenu(cmdString), !allProtected());
}
protected void addEditItems() {
addSeparator();
addCopy();
addPaste();
addCut();
addDelete();
}
/**
* Load menu items
*/
protected void initMenu() {
Object subMenu = null;
String cmdString = null;
setTitle(getTitleString());
// ===============================================
// Cut-Copy-Paste-Delete
// ===============================================
addSeparator();
addEditItems();
// ===============================================
// Insert/Delete Rows or Columns
// ===============================================
boolean enabled = false;
if (selectionType == MyTableInterface.COLUMN_SELECT
|| selectionType == MyTableInterface.ROW_SELECT) {
addSeparator();
subMenu = addSubMenu(loc.getMenu("Insert") + " ...", null);
if (selectionType == MyTableInterface.COLUMN_SELECT) {
cmdString = MenuCommand.InsertLeft.toString();
addSubMenuItem(subMenu, cmdString, loc.getMenu(cmdString),
true);
cmdString = MenuCommand.InsertRight.toString();
addSubMenuItem(subMenu, cmdString, loc.getMenu(cmdString),
true);
}
if (selectionType == MyTableInterface.ROW_SELECT) {
cmdString = MenuCommand.InsertAbove.toString();
addSubMenuItem(subMenu, cmdString, loc.getMenu(cmdString),
true);
cmdString = MenuCommand.InsertBelow.toString();
addSubMenuItem(subMenu, cmdString, loc.getMenu(cmdString),
true);
}
if (selectionType == MyTableInterface.COLUMN_SELECT) {
cmdString = MenuCommand.DeleteColumn.toString();
enabled = true;
addMenuItem(cmdString, getDeleteColumnString(), enabled);
}
if (selectionType == MyTableInterface.ROW_SELECT) {
cmdString = MenuCommand.DeleteRow.toString();
enabled = true;
addMenuItem(cmdString, getDeleteRowString(), enabled);
}
}
// ===============================================
// Create (Lists, Matrix, etc.)
// ===============================================
if (!isEmptySelection()) {
addSeparator();
subMenu = addSubMenu(loc.getMenu("Create"), null);
cmdString = MenuCommand.List.toString();
enabled = true;
addSubMenuItem(subMenu, cmdString, loc.getMenu(cmdString), enabled);
cmdString = MenuCommand.ListOfPoints.toString();
enabled = cp.isCreatePointListPossible(selectedCellRanges);
addSubMenuItem(subMenu, cmdString, loc.getMenu(cmdString), enabled);
cmdString = MenuCommand.Matrix.toString();
enabled = cp.isCreateMatrixPossible(selectedCellRanges);
addSubMenuItem(subMenu, cmdString, loc.getMenu(cmdString), enabled);
cmdString = MenuCommand.Table.toString();
enabled = cp.isCreateMatrixPossible(selectedCellRanges);
addSubMenuItem(subMenu, cmdString, loc.getMenu(cmdString), enabled);
cmdString = MenuCommand.PolyLine.toString();
enabled = cp.isCreatePointListPossible(selectedCellRanges);
addSubMenuItem(subMenu, cmdString, loc.getMenu(cmdString), enabled);
cmdString = MenuCommand.OperationTable.toString();
enabled = cp.isCreateOperationTablePossible(selectedCellRanges);
addSubMenuItem(subMenu, cmdString, loc.getMenu(cmdString), enabled);
}
// ===============================================
// Show Object or Label
// ===============================================
if (!isEmptySelection()) {
final GeoElement geo = geos.get(0);
boolean doObjectMenu = geo.isEuclidianShowable()
&& geo.getShowObjectCondition() == null
&& (!geo.isGeoBoolean() || geo.isIndependent());
boolean doLabelMenu = geo.isLabelShowable();
if (doObjectMenu || doLabelMenu) {
addSeparator();
if (doObjectMenu) {
addShowObject(geo);
}
if (doLabelMenu) {
cmdString = MenuCommand.ShowLabel.toString();
if (app.has(Feature.IMPROVE_CONTEXT_MENU)) {
addCheckBoxMenuItem(cmdString, loc.getMenu(cmdString),
loc.getMenu(MenuCommand.HideLabel.toString()),
geo.isLabelVisible());
} else {
addCheckBoxMenuItem(cmdString, loc.getMenu(cmdString),
geo.isLabelVisible());
}
}
}
// ===============================================
// Tracing
// ===============================================
if ((!app.isHTML5Applet() || !app.has(Feature.IMPROVE_CONTEXT_MENU))
&& geo.isSpreadsheetTraceable()
&& selectionType != MyTableInterface.ROW_SELECT) {
boolean showRecordToSpreadsheet = true;
// check if other geos are recordable
for (int i = 1; i < geos.size() && showRecordToSpreadsheet; i++) {
showRecordToSpreadsheet &= geos.get(i)
.isSpreadsheetTraceable();
}
if (showRecordToSpreadsheet) {
cmdString = MenuCommand.RecordToSpreadsheet.toString();
if (app.has(Feature.IMPROVE_CONTEXT_MENU)) {
addCheckBoxMenuItem(cmdString, loc.getMenu(cmdString),
MenuCommand.DontRecordToSpreadsheet.toString(),
geo.getSpreadsheetTrace());
} else {
addCheckBoxMenuItem(cmdString, loc.getMenu(cmdString),
geo.getSpreadsheetTrace());
}
}
}
}
// ===============================================
// Import Data
// ===============================================
if (enableDataImport()) {
cmdString = MenuCommand.ImportDataFile.toString();
addMenuItem(cmdString, loc.getMenu(cmdString) + " ...", true);
}
// ===============================================
// Spreadsheet Options
// ===============================================
if (isEmptySelection()) {
addSeparator();
cmdString = MenuCommand.SpreadsheetOptions.toString();
addMenuItem(cmdString, loc.getMenu(cmdString) + " ...", true);
}
// ===============================================
// Object properties
// ===============================================
if (app.getSelectionManager().selectedGeosSize() > 0
&& app.letShowPropertiesDialog()) {
addSeparator();
cmdString = MenuCommand.Properties.toString();
addMenuItem(cmdString, loc.getMenu(cmdString) + " ...", true);
}
}
protected void addShowObject(GeoElement geo) {
String cmdString = MenuCommand.ShowObject.toString();
addCheckBoxMenuItem(cmdString, loc.getMenu(cmdString),
geo.isSetEuclidianVisible());
}
private String getTitleString() {
// title = cell range if empty or multiple cell selection
String title = GeoElementSpreadsheet.getSpreadsheetCellName(column1,
row1);
if (column1 != column2 || row1 != row2) {
title += ":" + GeoElementSpreadsheet.getSpreadsheetCellName(column2,
row2);
}
// title = geo description if single geo in cell
else if (geos != null && geos.size() == 1) {
GeoElement geo0 = geos.get(0);
title = geo0.getLongDescriptionHTML(false, true);
if (title.length() > 80) {
title = geo0.getNameDescriptionHTML(false, true);
}
}
return title;
}
/**
* @return true if data file can be read locally
*/
public boolean enableDataImport() {
// to be overridden in Desktop
return false;
}
private boolean allProtected() {
boolean allFixed = true;
if (geos != null && geos.size() > 0) {
for (int i = 0; (i < geos.size() && allFixed); i++) {
GeoElement geo = geos.get(i);
if (!geo.isProtected(EventType.REMOVE)) {
allFixed = false;
}
}
}
return allFixed;
}
/**
* @return true if no GeoElements selected
*/
public boolean isEmptySelection() {
return (app.getSelectionManager().getSelectedGeos().isEmpty());
}
private String getDeleteRowString() {
String strRows;
if (row1 == row2) {
strRows = app.getLocalization().getPlain("DeleteRowA",
Integer.toString(row1 + 1));
} else {
strRows = app.getLocalization().getPlain("DeleteRowsAtoB",
Integer.toString(row1 + 1), Integer.toString(row2 + 1));
}
return strRows;
}
private String getDeleteColumnString() {
String strColumns;
if (column1 == column2) {
strColumns = app.getLocalization().getPlain("DeleteColumnA",
GeoElementSpreadsheet.getSpreadsheetColumnName(column1));
} else {
strColumns = app.getLocalization().getPlain("DeleteColumnsAtoB",
GeoElementSpreadsheet.getSpreadsheetColumnName(column1),
GeoElementSpreadsheet.getSpreadsheetColumnName(column2));
}
return strColumns;
}
// ===============================================
// Command Processor
// ===============================================
/**
* Performs menu item command for given command key
*
* @param cmdString
* command key
*/
public void doCommand(String cmdString) {
boolean succ = false;
switch (MenuCommand.valueOf(cmdString)) {
default:
// do nothing
break;
case ShowObject:
cmdShowObject();
break;
case ShowLabel:
cmdShowLabel();
break;
case RecordToSpreadsheet:
cmdRecordToSpreadsheet();
break;
case Copy:
cmdCopy();
break;
case Duplicate:
cmdCopy();
cmdPaste();
break;
case Paste:
cmdPaste();
break;
case Cut:
succ = table.getCopyPasteCut().cut(column1, row1, column2, row2);
if (succ) {
app.storeUndoInfo();
}
break;
case Delete:
case DeleteObjects:
succ = table.getCopyPasteCut().delete(column1, row1, column2, row2);
if (succ) {
app.storeUndoInfo();
}
break;
case InsertLeft:
cp.insertColumn(column1, column2, true);
break;
case InsertRight:
cp.insertColumn(column1, column2, false);
break;
case InsertAbove:
cp.insertRow(row1, row2, true);
break;
case InsertBelow:
cp.insertRow(row1, row2, false);
break;
case DeleteColumn:
cp.deleteColumns(column1, column2);
break;
case DeleteRow:
cp.deleteRows(row1, row2);
break;
case List:
cp.createList(selectedCellRanges, true, false);
break;
case ListOfPoints:
cmdListOfPoints();
break;
case Matrix:
cp.createMatrix(column1, column2, row1, row2, false);
break;
case Table:
cp.createTableText(column1, column2, row1, row2, false, false);
break;
case PolyLine:
cmdPolyLine();
break;
case OperationTable:
cp.createOperationTable(selectedCellRanges.get(0));
break;
case ImportDataFile:
cmdImportDataFile();
break;
case SpreadsheetOptions:
cmdSpreadsheetOptions();
break;
case Properties:
cmdProperties();
break;
}
}
private void cmdCopy() {
table.getCopyPasteCut().copy(column1, row1, column2, row2, false);
}
private void cmdPaste() {
boolean succ = table.getCopyPasteCut().paste(column1, row1, column2,
row2);
if (succ) {
app.storeUndoInfo();
}
table.getView().rowHeaderRevalidate();
}
// =============================
// Action Commands
// =============================
/**
* Hide/show selected cells in EV
*/
public void cmdShowObject() {
for (int i = geos.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos.get(i);
geo1.setEuclidianVisible(!geo1.isSetEuclidianVisible());
geo1.updateRepaint();
}
app.storeUndoInfo();
}
/**
* Hide/show labels of selected cells in EV
*/
public void cmdShowLabel() {
for (int i = geos.size() - 1; i >= 0; i--) {
GeoElement geo1 = geos.get(i);
geo1.setLabelVisible(!geo1.isLabelVisible());
geo1.updateRepaint();
}
app.storeUndoInfo();
}
/**
* Trace selected cells in the spreadsheet TODO: is this needed?
*/
public void cmdRecordToSpreadsheet() {
GeoElement geo = geos.get(0);
GeoElement geoRecordToSpreadSheet;
if (geos.size() == 1) {
geoRecordToSpreadSheet = geo;
} else {
geoRecordToSpreadSheet = app.getKernel().getAlgoDispatcher()
.List(null, geos, false);
geoRecordToSpreadSheet.setAuxiliaryObject(true);
}
table.getView().showTraceDialog(geoRecordToSpreadSheet, null);
}
/**
* Create list of points from selected cells
*/
public void cmdListOfPoints() {
GeoElement newGeo = cp.createPointGeoList(selectedCellRanges, false,
true, true, true, true);
app.getKernel().getConstruction()
.addToConstructionList(newGeo.getParentAlgorithm(), true);
newGeo.setLabel(null);
}
/**
* Create PolyLine object from selected cells
*/
public void cmdPolyLine() {
GeoElement newGeo = cp.createPolyLine(selectedCellRanges, false, true);
app.getKernel().getConstruction()
.addToConstructionList(newGeo.getParentAlgorithm(), true);
newGeo.setLabel(null);
}
/**
* Import data file
*/
public void cmdImportDataFile() {
// to be overridden
}
/**
* Open spreadsheet options dialog
*/
public void cmdSpreadsheetOptions() {
app.getDialogManager().showPropertiesDialog(OptionType.SPREADSHEET,
null);
}
/**
* Open Object Properties dialog
*/
public void cmdProperties() {
app.getDialogManager().showPropertiesDialog(OptionType.OBJECTS, null);
}
// ==================================================
//
// GUI methods to be implemented in subclasses.
//
// ==================================================
/**
* @return PopUp menu container
*/
public Object getMenuContainer() {
// to be overridden
return null;
}
/**
* Create popUp menu using the initMenu() method.
*/
public void createGUI() {
// to be overridden
}
/**
* @param cmdString
* Action command key (and icon key)
* @param text
* Text to be displayed in the menu
* @param enabled
* Flag to enable/disable the menu item
*/
public void addMenuItem(final String cmdString, String text,
boolean enabled) {
// to be overridden
}
/**
* @param cmdString
* Action command key (and icon key)
* @param text
* Text to be displayed in the menu
* @param isSelected
* flag Flag to set selection state
*/
public void addCheckBoxMenuItem(final String cmdString, String text,
boolean isSelected) {
// to be overridden
}
/**
* @param cmdString
* Action command key (and icon key)
* @param selected
* Text of selected menu item
* @param nonSelected
* Text of non-selected menu item
* @param isSelected
* flag Flag to set selection state
*/
public void addCheckBoxMenuItem(final String cmdString, String nonSelected,
String selected, boolean isSelected) {
// to be overridden
}
/**
* @param text
* Text to be displayed in the menu
* @param cmdString
* Action command key (and icon key)
* @return Menu object
*/
public Object addSubMenu(String text, String cmdString) {
// to be overridden
return null;
}
/**
* @param menu
* Menu container to add new menu item
* @param cmdString
* Action command key (and icon key)
* @param text
* Text to be displayed in the menu
* @param enabled
* Flag to enable/disable the menu item
*/
public void addSubMenuItem(Object menu, final String cmdString, String text,
boolean enabled) {
// to be overridden
}
/**
* Add separator bar to menu
*/
public void addSeparator() {
// to be overridden
}
/**
* Sets the menu title and adds mouse handling to close the menu if clicked.
*
* @param str
* Title string to add to top of menu
*/
public void setTitle(String str) {
// to be overridden
}
}