Appendix A - Miscellaneous
A.1 Shortcuts
A.1.1 Keyboard Shortcuts
Several of the menu options have keyboard shortcuts which are labelled next to the option. In addition to these facilities, there are further shortcuts that you may find useful. This first table lists shortcuts that are available when the focus in on the sheet (such as when you start mtCellEdit).
Home | Move to column 1 in the current row |
Home + CTRL | Move to the row 1 column 1 cell |
End | Move to the last column in the current row |
End + CTRL | Move to the last column and the last row |
Page Up | Scroll the sheet a page up |
Page Up + ALT | Scroll the sheet a page left |
Page Down | Scroll the sheet a page down |
Page Down + ALT | Scroll the sheet a page right |
Arrow keys | Move the selection to another cell |
Arrow keys + SHIFT | Change the currently selected area |
Arrow keys + CTRL | Move to the next active row (in the sheet) or column (in this row) |
This table lists the keyboard shortcuts you can use when you are editing the cell text in the cell entry box:
Escape | Cancel current operation |
Enter/Return | Set cell text and move the cursor down one cell |
Tab | Set cell text and move the cursor right one cell |
Tab + CTRL | Set cell text and move the cursor left one cell |
Up/Down Arrow Key | Set cell text and move the cursor up or down one cell |
All of these actions are then following by the focus moving to the sheet again. The Escape key also returns focus to the sheet while editing the cell range box or editing the graph text.
A.1.2 Mouse Shortcuts
Left button | Select a cell or area (clicking or dragging). When the cursor focus is in the cell entry box, a left click puts a cell reference into the entry (SHIFT=absolute row; CTRL=absolute column). |
Right button | Select the second corner of an area (clicking or dragging). When the cursor focus is in the cell entry box, a right click puts a ':' character and the cell reference into the entry (SHIFT=absolute row; CTRL=absolute column). |
A.2 Supported File Types
CED | Load/Save | mtCellEdit book of sheets and their preferences. | Each CED file is a ZIP archive containing TSV or Ledger files, and preferences information. |
TSV | Load/Save | Tab Separated Values (single sheet) | Up to 1,000,000 rows, 1,000,000 columns, covering at most 1,000,000,000 cells. |
Ledger | Load/Save | A ledger of all cell content (single sheet) | Up to 1,000,000,000 rows and columns. |
CSV | Load/Save | Comma Separated Values (single sheet) | Up to 1,000,000 rows, 1,000,000 columns, covering at most 1,000,000,000 cells. When loading a file, if its name ends with .csv (case insensitive), it is assumed to be a CSV file, with all other files being TSV. |
A.2.1 CED Files
A CED file is in fact a ZIP archive file. You can use whatever file extension you like. I chose the ZIP archive format because it can be opened using any operating system, thus allowing anyone to open the collection of sheets easily and independently of the mtCellEdit program. The ZIP archive contains files in the following form:
Internal Filename | Description |
filename/sheet/* | Each sheet in the book is stored here as a TSV/Ledger file, with its name being in place of *. |
filename/values/* | This is an optional section used when saving the values within the CED file. The purpose of saving cell values is: (*) It is useful for archiving purposes as the data can be read by any spreadsheet program because no formulas are saved as they are replaced by the numerical values. (*) Complex sheets with convoluted cell relationships do not require numerous recalculations between sessions to get correct values (mtCellEdit uses a very simple top-down bottom-up recalculation algorithm that can be tricked when using several forward/backward references in sheets). |
filename/graph/* | This is where the text for each graph is stored. |
filename/prefs/book.txt | This file contains book, sheet, and cell preferences. By keeping this data separate from the sheet data it makes it much easier to transfer the sheet data to other spreadsheet programs. |
In all cases 'filename' is the name of the original file saved, so this would be 'test' if you saved 'test.zip'. On loading, any other file is ignored, but is stored in memory so when the book is saved again these files will be retained in the new CED/ZIP file (with the same time and date stamps).
A.2.2 TSV Files
A TSV file (Tab Separated Value) is my preferred file format for sheets as it can be read by any good spreadsheet program. I prefer it over CSV because its simpler. The CSV format has the major flaw that commas can be used in a cell thus complicating the encoding of each cell text (i.e. the inefficient " quotation system). TSV files are simpler as the tab character is never used in a cell, and therefore its much quicker to parse this file format than any other encoding.
A.2.3 Ledger Files
Ledger files are designed for the very rare occasion when you have a very large but sparse sheet, such as 10,000 cells of content within a 1,000,000,000 x 1,000,000,000 sheet. Saving this to a TSV or CSV file would be grossly inefficient because of the duplication of empty cells. The down side of using ledger files is that the format cannot be read by other spreadsheet programs.
A.2.4 CSV Files
Despite being widely used, the CSV file format has no official specification, and sadly this means that different programs create slightly different CSV files. As a result of this some files may not load properly into mtCellEdit (or other spreadsheet programs). However, mtCellEdit should load all RFC-4180 compliant files as long as they don't contain newlines inside a field.
A.3 Functions
A function returns a number. Valid function syntax is:
function_name( [ARG]... )
Arguments are separated by a , or ; character.
A NUM is a decimal number, a function, or a CELLREF. A STRING is a collection of characters with " quotes, e.g. "Hello".
A CELLREF takes the r1c1 notation, e.g.
r1c1 | Absolute reference. |
r[-1]c[-1] | Relative reference. |
r_c_ | _ is a shorthand for the maximum row/column number. |
A RANGE takes the form:
CELLREF:CELLREF
Cells and ranges in other sheets can be referenced by using:
'sheet_name'r1c1
Here is a complete list of functions mtCellEdit understands when placed after an = character in the cell text:
Function | Arguments | Description |
abs | NUM | Absolute value. e.g. abs(-2) = 2 |
acos | NUM | Inverse cosine |
asin | NUM | Inverse sine |
atan | NUM | Inverse tangent |
atan2 | Inverse tangent (two arguments) | |
NUM | x | |
NUM | y | |
average | RANGE | Calculate average of all numbers in the range |
ceil | NUM | Round a decimal number up. e.g. ceil(2.1) = 3 |
cos | NUM | Cosine |
cosh | NUM | Hyperbolic cosine |
count | RANGE | Count the number of cells with numbers (i.e. ignore text and errors) |
counta | RANGE | Count non-empty cells |
countblank | RANGE | Count empty cells |
countif | Count the number of numerical cells that pass a test | |
RANGE | Range of cells to check | |
STRING | Conditional test "<" "<=" ">" ">=" "=" "<>" | |
NUM | Number to test each cell in the range with | |
date | Get numerical representation of a date. date( 0, 1, 1 ) = 0 | |
NUM | Year 0..5879609 | |
NUM | Month 1..12 | |
NUM | Day 1..31 | |
day | NUM | Return day of month of a given numerical date |
degrees | NUM | Converts a radian number to degrees |
exp | NUM | Raise e to the power of NUM |
fact | NUM | Return factorial of NUM when 0 <= NUM <= 170 |
floor | NUM | Round a decimal number down. e.g. floor(2.1) = 2 |
frac | NUM | Return the fractional part of a decimal. e.g. frac( -1.234 ) = -0.234 |
hour | NUM | Return the hour of a date/time number 0..23 |
if | e.g. if( 1, 2, 3 ) = 2; if( 0, 2, 3 ) = 3; if( 1<2, 2, 3 ) = 2 | |
NUM | 0=FALSE else TRUE | |
NUM | Returned if TRUE | |
NUM | Returned if FALSE | |
int | NUM | Rounds down to the nearest integer |
large | Return the largest number in the range as per rank | |
RANGE | ||
NUM | Rank (1=largest 2=2nd largest, etc.) | |
ln | NUM | Natural logarithm |
max | RANGE or NUM | Return the maximum number from the range(s), or the number(s). |
... | You are allowed to enter up to 10 function arguments. | |
median | RANGE | Return the median number in the range |
min | RANGE or NUM | Return the minimum number from the range(s), or the number(s). |
... | You are allowed to enter up to 10 function arguments. | |
minute | NUM | Return the minute of a date/time number 0..59 |
mod | Return modulo of a number. e.g. mod( 5, 2 ) = 1 | |
NUM | Number | |
NUM | Modulo | |
month | NUM | Return the month of a date/time number 1..12 |
now | Return the current date/time number | |
offset | Return the value in another cell via an offset | |
#CELLREF | Start | |
NUM | Rows offset from CELLREF | |
NUM | Columns offset from CELLREF | |
percentile | Return the given percentile of the range. | |
RANGE | ||
NUM | Percentile 0.0 .. 1.0 | |
percentrank | Return the percentage rank of the number given. 0.0 .. 1.0 | |
RANGE | ||
NUM | This must be >= to the minimum and <= to the maximum number in the range | |
pi | PI | |
radians | NUM | Converts a degree number to radians |
rand | Random number | |
rank | Return the rank of a given number. 1=lowest/highest. | |
NUM | Number (must be in RANGE somewhere) | |
RANGE | ||
NUM | 0=lowest 1=highest | |
rgb | Return a packed RGB number. | |
NUM | 0..255 | |
NUM | 0..255 | |
NUM | 0..255 | |
round | NUM | Round this numbers digits. |
NUM | 0 rounds at decimal point, <0 rounds to the left of the decimal point by that number of digits, >0 rounds to the right of the decimal point by that number of digits. | |
second | NUM | Return the seconds of a date/time number 0..59 |
sin | NUM | Sine |
sinh | NUM | Hyperbolic sine |
small | Return the smallest number in the range as per rank. | |
RANGE | ||
NUM | Rank (1=smallest 2=2nd smallest, etc.) | |
sqrt | NUM | Square root |
strvlookup | Look up a string in a range, and return a value from another cell in that row. | |
#CELLREF | Text to find is in this cell | |
RANGE | Range to scan for text | |
NUM | Column index offset, relative to RANGE. 1=first column to right of RANGE | |
sum | RANGE | Sum all numbers in the range |
sumif | Sum the contents of numerical cells that pass a test. | |
RANGE | Range of cells to test | |
STRING | Conditional test "<" "<=" ">" ">=" "=" "<>" | |
NUM | Number to action the test on | |
#CELLREF | Top left cell of sum range | |
tan | NUM | Tangent |
tanh | NUM | Hyperbolic tangent |
time | Get numerical representation of a time. time( 0, 0, 0 ) = 0.0; time( 12, 0, 0 ) = 0.5 | |
NUM | Hours | |
NUM | Minutes | |
NUM | Seconds | |
today | Return today's date number | |
trunc | NUM | Truncate this numbers digits. |
NUM | 0 truncates at decimal point, <0 truncates to the left of the decimal point by that number of digits, >0 truncates to the right of the decimal point by that number of digits. | |
vlookup | Look up a value in a range, and return a value from another cell in that row. | |
NUM | Number to find | |
RANGE | Range to scan for 'NUM' | |
NUM | Column index offset, relative to RANGE. 1=first column to right of RANGE | |
weekday | NUM | Return the weekday of a date/time number. 1..7 |
year | NUM | Return the year of a date/time number |
A.4 Cell Formats
One of the cell preferences is the 'format' which determines how the cell is rendered. By choosing a different format and adjusting other cell preferences the output can be tailored as required.
Format | Preferences | Description |
General | format_datetime | Render a cell according to its internal type as determined by the parser. This could be a number, text, a date, etc. |
num_thousands | ||
Text | - | Render the exact text in the cell. |
Fixed Decimal | num_decimal_places | Render a decimal number according to the number of prescribed decimal places. |
num_thousands | ||
Hexadecimal | num_zeros | Render a hexadecimal number, with the option of padding for leading zeros. |
Binary | num_zeros | Render a binary number, with the option of padding for leading zeros. |
Scientific | num_decimal_places | Render a number using scientific notation for a prescribed number of decimal places. |
Percentage | num_decimal_places | Render a number as a percentage, with 1.0 being 100.0% |
num_thousands | ||
Datetime | format_datetime | Render a number as a date and time according to a prescribed form. |
The format_datetime text string expands the following special characters:
d | Day number. |
dd | Day number with a leading zero. |
ddd | Day name, abbreviated. |
dddd | Day name, full. |
m | Month number. |
mm | Month number with a leading zero. |
mmm | Month name, abbreviated. |
mmmm | Month name, full. |
y | Year number. |
yy | Year number (2 digits) with a leading zero. |
H | Hour number. |
HH | Hour number with a leading zero. |
M | Minute number. |
MM | Minute number with a leading zero. |
S | Second number. |
SS | Second number with a leading zero. |
\ | Render the next character as itself. This allows the rendered text to include the d m y H M S \ characters. |
All other characters encountered are directly placed into the rendered string.
A.5 Error Codes
When the parser finds an error it displays an error in the form:
Err:x,y
The y represents the number of characters that were parsed before the error occurred. The x represents the error itself as described in this table:
0 | Syntax error |
1 | Memory error |
2 | Bad function name |
3 | Bad function token |
4 | Bad function argument |
5 | Bad function operation |
6 | Bad number |
7 | Bad sheet reference |
8 | Infinity |
9 | Not a number |
10 | Bad cell reference |
11 | Cell text too long |
A.6 Limitations
As with all software, mtCellEdit has some limitations. In some cases any attempt to overcome these limitations would invalidate the purpose and philosophy of the project. Therefore I am documenting these limitations in order to explain the policy decisions I have taken. However, mtCellEdit is free software so if anyone disagrees then they are free to fork the code and implement their own ideas.
A.6.1 Localization
mtCellEdit is entirely written in English, with all language and numerical notation being geared towards that locale. There are many different languages and numerical systems that could be supported by a spreadsheet program, but to do so would complicate the program and the data files that the program creates.
For example, one of the rules I insist on with mtCellEdit is whatever text the user enters into a cell this must be exactly what gets recorded in the saved file. I have a particular dislike of programs that subvert user input via optimizations, or corrections (such as removing spaces in formulas or capitalization of certain letters).
This causes a problem when saving data to a TSV file and moving the data between locales that use a different decimal point system. For example if I have a TSV file with 1.23 in it, my English locale will interpret that as a decimal number. However in a French locale this would not be recognised as a number and would be treated as a text string. Naturally the reverse would also be true with 1,23 being a decimal number in the French locale but not the English locale.
In other words we have a problem regarding data portability and non-deterministic program behaviour. From version 1.4.0 of mtCellEdit I avoided this problem by enforcing a C locale when the program starts, so all data is interpreted using the same standards whatever locale the operating system happens to be using. When not using the GUI and using libmtcelledit directly the calling program will need to set the locale to 'C' otherwise there may be problems.
Another example of localization regards right to left rendering of cells, and the use of exotic fonts and various font substitutions. Even if I had the time and expertise to implement such features, this would dramatically bloat the program, and complicate many parts of the program structure.
Because of these issues, I have decided to keep mtCellEdit a solely English locale project. I do not have the time or inclination to change this.
A.6.2 Spreadsheet File Formats
I have deliberately chosen to not support mainstream file formats for other spreadsheet programs as they are reliant on complex binary or XML files. I have seen these various formats come and go over the years as the programs that use them become popular, and then fade into obscurity. In the beginning the 'industry standard' program was Visicalc, then Lotus 1-2-3, and most recently Excel. Each program has also adopted various major revisions to its file format over its lifetime, which makes data portability even more of a problem.
Due to the policy decisions of the creators, those 'industry standard' programs are continuing to use data formats that will not stand the test of time, and are a bad choice as a data archive format. Therefore I refuse to support them, and this is why I prefer to use simple text based formats instead. Somebody using the Awk program on a Unix system in 1980 could easily manipulate a TSV file, as they can today, and as they will be able to do for decades to come. In other words this file type is built to stand the test of time, and is therefore the best choice as an archive format.
In short, mtCellEdit has never, and will never support binary or XML based data files.
A.6.3 Dates
The year in a date is only valid from 0 to 5879609.
All years are interpreted literally, so an abbreviated two digit year is considered different to a four digit year. For example 25/10/12 is not the same as 25/10/2012. This strictness avoids ambiguity and problems like the millennium bug.
If you encounter a datafile which contains a two digit year that you wish to convert to a four digit year you would do the following:
- Select the relevant cells you want to change.
- Select the menu option "Edit - Fix 2-digit Years"
By default this assumes the years are to be changed to some time in the last 50 years or the coming 49 years. If you want to change the start year to something else you must change the Program Preference "date.2digit_year_start".
A.6.4 Numbers
Each cell contains a number which is stored internally as a double precision floating point number. Typically this means it is accurate to 15 significant decimal digits.
When displaying this number as a binary or hexadecimal number the accuracy is about 52 bits.
A.7 Graph Language
Graphs are defined in a block of text using my own data language called utree (which is part of libmtKit). Here is a simple example which illustrates how to use instructions that contain various attribute values, with various useful comments:
/* This is a comment - it can contain any text. */ { instruction_name attribute="value" another_attribute="value" "This contains spaces"="Backslashes and quotations must be backslashed first: \\ and \" - easy isn't it!" sheet="Sheet Name" /* Normally attribute values are only used in the instruction that defines them. However, the 'sheet' attribute value is special as it is used by all subsequent instructions until it is re-defined. */ } { another_instruction /* Comments can appear anywhere. This instruction contains no attributes, so the default values are used. See below for a complete list of default attribute values. */ }
All attribute values are considered as double precision floating point numbers unless otherwise stated below. You can use spreadsheet notation and functions such as "2.0 + 2.1", "2011-10-9", "rgb(1,2,3)", "0xFFAA11" or even use cell references (use this wisely as the sheet attribute must be set properly).
A.7.1 Conceptual Outline
The general sequence of a graph should follow this pattern:
- Define the page, graph, and plot areas.
- Define the X and Y axis.
- Plot the axis text and markings. (OPTIONAL)
- Plot any gridlines that appear beneath the graphs. (OPTIONAL)
- Plot the shapes and lines using data from a sheet. (OPTIONAL)
Any number of graphs and gridlines can be used, each with their own X and Y axis settings.
A.7.2 Page Layout
The page is initially defined as a physical width and height, with the origin of (0,0) being at the top left corner. Each unit is 1/72 of an inch. This page contains a 'graph' rectangle which itself contains a 'plot' rectangle which is used to do all of the final plotting on using the logical X and Y axis settings as prescribed.
The 'graph' area contains top, bottom, left and right axis titles, with additional text labels and axis markings (all optional).
A.7.3 Graph Instructions and Attributes
Here is a table with a list of instructions and attributes that they use. In addition, all drawing or plotting instructions (i.e. page, graph, plot, plot_*) will be affected by:
- antialias
- arrowhead
- fill_color
- line_color
- line_size
- text_color
- text_size
Instruction | Attributes Used | Notes |
graph | x_pad | These attributes are in physical points. The padding is the gap between the outer graph rectangle and the plot rectangle. |
y_pad | ||
page | height | These attributes are in physical points. The padding is the gap between the outer page and the graph rectangle. This should always be the first instruction. Although the sheet attribute isn't required here, it can be useful to define it here if only one sheet is to be used as a data source. By doing this you avoid the need to keep defining it later. |
width | ||
x_pad | ||
y_pad | ||
plot | x_pad | These attributes are in physical points. The padding is the gap between the outer plot rectangle and the inner plot rectangle. In other words the total gaps between the outer graph rectangle and the outer plot rectangle is the sum of the two pads defined in both instructions. |
y_pad | ||
plot_box | data | data points to a range of cells (e.g. r1c1:r_c1). These are parsed top down with 5 columns for x1, x2, y1, y2, text. The coordinates relate to the logical coordinates in the plot area and are clipped to that rectangle. Text (if present) is rendered inside the box at the prescribed settings. |
plot_ellipse | data | data as plot_box. Text (if present) is rendered inside the ellipse at the prescribed settings. |
plot_graph_bar | data | data points to a single line (horizontal or vertical) of cells, such as r1c1:r1c_. These cell values are used to draw the graph in the plot area. The values are interepreted as Y coordinates, with X starting at the x_axis minimum, and incremented according to gap. |
gap | ||
plot_graph_line | data | data as plot_graph_bar |
gap | ||
plot_line | data | data as plot_box. Text (if present) is rendered at the end of the x2, y2 coordinate. If the arrowhead value is greater than 0 this is rendered at the end of the x2, y2 coordinate. |
plot_x_axis | data | If data is used then this is a horizontal or vertical set of cells that are used to label each axis mark. |
gap | ||
label_format | If label_format is set then use this as a sheet cell reference to render the numbers in this form. | |
size | If size is defined draw marks along the axis at gap intervals. | |
text | If text is defined, draw the axis title as this, with the prescribed justification. | |
x_justify | If you plan to use titles and axis labels of simultaneously it is wise to have two instructions for this: one for the title and one for the labels, so that the text sizes and justifications don't clash. | |
y_justify | ||
plot_x_axis_grid | gap | Draw horizontal lines across the plot area parallel with the X axis at intervals defined by gap. |
min | min can be used to shift the modulo origin to something other than 0, which is useful if the axis doesn't begin at 0. | |
plot_x_axis_top | as plot_x_axis | as plot_x_axis |
plot_y_axis | as plot_x_axis | as plot_x_axis |
plot_y_axis_grid | gap | Draw vertical lines across the plot area parallel with the Y axis at intervals defined by gap. |
min | min can be used to shift the modulo origin to something other than 0, which is useful if the axis doesn't begin at 0. | |
plot_y_axis_right | as plot_x_axis | as plot_x_axis |
x_axis | min | This sets the logical limits of the plot area. If min is greater than max then the direction of the plotting and the axis is reversed, i.e. from right to left. |
max | ||
y_axis | min | This sets the logical limits of the plot area. If min is greater than max then the direction of the plotting and the axis is reversed, i.e. from bottom to top. |
max |
A.7.4 Default Attribute Values
Attribute | Value | Notes |
antialias | 1 | This only affects bitmap rendering. 0=Don't antialias; 1=Do. |
arrowhead | 0 | At values greater than 0 an arrowhead is drawn with this size at the end of each line. |
data | NULL | Text string. This is usually a cell range for the graphs. |
fill_color | 0xFFFFFF | When greater or equal to 0 fill using this colour. Otherwise don't fill. |
gap | 0 | |
line_color | 0 | When greater or equal to 0 draw lines using this colour. Otherwise don't draw anything. |
line_size | 1 | Lines are drawn with this thickness. |
max | 0 | |
min | 0 | |
sheet | Inherited | Text string set to NULL at first. This is the only default attribute that is inherited from the previous instructions. This should contain text that refers to a sheet in the book. If this sheet doesn't exist, its reference is cleared to NULL. |
size | 0 | |
text | NULL | Text string. |
text_color | 0 | When greater or equal to 0 draw text using this colour. Otherwise don't draw anything. |
text_size | 12 | Font size in units. |
x_justify | 0.5 | 0=Justify to the left; 0.5=Centralize; 1.0=Justify to the right. |
x_pad | 0 | |
y_justify | 0.5 | 0=Justify to the top; 0.5=Centralize; 1.0=Justify to the bottom. |
y_pad | 0 |
A.8 Preferences
Preferences are held in memory as per the C structures defined in the source code. They are also held in CED/ZIP files as explained in A.2.1.
A.8.1 Cell
Key | Data | Notes |
align_horizontal | INTEGER | 0=None, 1=Left, 2=Centre, 3=Right |
text_style | INTEGER | Bit field |
border_color | INTEGER | Packed RGB 0xRRGGBB |
border_type | INTEGER | Bit field |
color_background | INTEGER | Packed RGB 0xRRGGBB |
color_foreground | INTEGER | Packed RGB 0xRRGGBB |
format | INTEGER | 0=General, 1=Text, 2=Fixed Decimal, 3=Hexadecimal, 4=Binary, 5=Scientific, 6=Percentage, 7=Datetime |
format_datetime | STRING | |
locked | INTEGER | 0=Unlocked, 1=Locked |
num_decimal_places | INTEGER | |
num_thousands | STRING | Thousands separator character |
num_zeros | INTEGER | Pad with leading zeros in binary and hexadecimal cell formats |
text_prefix | STRING | |
text_suffix | STRING | |
width | INTEGER | Only used in row 0 for setting column width |
A.8.2 Sheet
Key | Data |
cursor_c1 | INTEGER |
cursor_c2 | INTEGER |
cursor_r1 | INTEGER |
cursor_r2 | INTEGER |
locked | INTEGER |
split_c1 | INTEGER |
split_c2 | INTEGER |
split_r1 | INTEGER |
split_r2 | INTEGER |
start_col | INTEGER |
start_row | INTEGER |
A.8.3 Book
Key | Data | Notes |
active_graph | STRING | |
active_sheet | STRING | |
author | STRING | When creating a new book, this is populated with the users name (from the operating system) |
auto_recalc | INTEGER | 0=None, 1=Sheet, 2=Book |
comment | STRING | |
disable_locks | INTEGER | 0=Enable Locks in sheets/cells, 1=Disable Locks in sheets/cells |
A.8.4 State
The state is an area in mtCellEdit and mtCedCLI that stores information regarding the page for exporting the sheet to a paged PDF. mtCellEdit stores changes to this information in the ~/.mtcelledit preferences file for each session, whereas mtCedCLI always starts each session with the defaults.
Key | Data | Default | Notes |
page_font_size | INTEGER | 10 | |
page_footer_centre | INTEGER | 0 | 0=None, 1=Filename (long), 2=Filename (short), 3=Sheet Name, 4=Page Number, 5=Date, 6=Date and Time |
page_footer_left | INTEGER | 6 | 0=None, 1=Filename (long), 2=Filename (short), 3=Sheet Name, 4=Page Number, 5=Date, 6=Date and Time |
page_footer_right | INTEGER | 4 | 0=None, 1=Filename (long), 2=Filename (short), 3=Sheet Name, 4=Page Number, 5=Date, 6=Date and Time |
page_header_centre | INTEGER | 0 | 0=None, 1=Filename (long), 2=Filename (short), 3=Sheet Name, 4=Page Number, 5=Date, 6=Date and Time |
page_header_left | INTEGER | 2 | 0=None, 1=Filename (long), 2=Filename (short), 3=Sheet Name, 4=Page Number, 5=Date, 6=Date and Time |
page_header_right | INTEGER | 3 | 0=None, 1=Filename (long), 2=Filename (short), 3=Sheet Name, 4=Page Number, 5=Date, 6=Date and Time |
page_margin_x | INTEGER | 10 | |
page_margin_y | INTEGER | 10 | |
page_mm_height | INTEGER | 210 | |
page_mm_width | INTEGER | 297 |
A.9 File Handling
When editing a file in mtCellEdit the titlebar describes the file IO permission via a code:
{} | Book has no filename yet. |
{RW} | File is Read/Write (i.e. any other program can write to it). |
{RWL} | File is Read/Write and Locked against other programs writing to it via a temporary read only file permission on disk. |
{RO} | File is Read Only and cannot be saved using this filename. |
At all times you can edit the book in memory but you can only save using the current filename if a W is present in the title bar.
A.9.1 File Locks (RWL & RO)
By default mtCellEdit loads data from a file and edits this in memory until the user saves the data. This is pefectly reasonable under most circumstances, but occasionally this is unsafe such as when an absent minded user accidentally opens the same file in two mtCellEdit instances. If the user has unsaved data in instance 1, and then loads the same file into instance 2, these changes will not appear in instance 2. If the user was to make changes in instance 2 and save those changes this could create real confusion and potentially lose data.
In order to avoid such problems between mtCellEdit instances, or even other programs editing files, you can switch on a locking mechanism which switches off the write permissions on the file while it is being edited. Then other programs are stopped from making changes until mtCellEdit finishes editing it and the original file permissions are restored.
In the program preferences, filter for 'lock' and you should find:
file_lock_load file_lock_save
Switch both to RWL and then every time you load and save a file a Re-Write Lock is enabled. Then any other program, including multiple mtCellEdit instances, cannot modify the file while it is still being edited by the original mtCellEdit instance.
You can also force all files to be Read-Only after loading or saving if that suits your needs.
If you have the {RWL} setting on, it may fail under a specific circumstance and be {RW}. This happens when a user has permission to write to the file but is not able to change the write permission to get a lock. If this is because another user owns the file, or you are not in the correct file group, you can simply save the file to get {RWL} locking enabled which changes the ownership of the file.
A.9.2 Saving (Temporary File)
In mtCellEdit and mtCedCLI, when saving a file to disk a temporary file is used to initially write the data to. This is to protect against power failure, OS failure, hardware failure, etc causing the original file data to be lost before the new data is saved. Once the temporary file has been successfuly saved it is renamed to the designated filename to complete the operation.
A.10 Historic Design Choices
When I first started the mtCellEdit project, some design decisions were forced on me by the limited hardware and software available at the time. As things changed over time I was able to improve the project by taking advantage of improvements to hardware such as faster devices. Likewise, the software that mtCellEdit relies on has also changed. For example when I started I used GTK+ version 2, which continued until 2016 when I switched over to using Qt version 5 by default.
A.10.1 Font Rendering
During 2010-2016, versions 1.0 to 2.6 of mtCellEdit rendered text directly using FreeType or a hard coded ASCII font, which was the fastest method available and was desirable on slower hardware manufactured before 2005. However, by 2016, even cheap PC hardware was fast enough to comfortably use Pango to render fonts with nice luxuries such as kerning and font substitution. By 2022 and version 3.6, I started using Cairo to render what appeared on screen which enables luxuries such as multicoloured emojis on many systems, such as 💯 and 🤩. PC hardware manufactured after 2014 should have enough speed to do this efficiently (as proven by a cheap PC such as the Raspberry Pi). A user preference can be selected to change the screen rendering back to Pango (main_window_renderer) if the user wants things rendered slightly faster.