Last week, we added a modify dialog for our page break style manager, to let us rename and delete page break styles. This got us to a point where we have what I’d consider “minimal functionality” required to have a useful script, but let’s take it a step further, and add in a re-order function. It’s very useful to be able to shuffle the order around so you can have all styles, for a single client, grouped together. You don’t have to constantly search through a list anymore. While we’re at it, we can add in functionality to disable buttons if they are not applicable to our selection. For example, if we don’t have a selection, everything should be disabled. if we have the top list item selected, the move up button should be disabled, because we obviously can’t move the top item up even higher. The opposite applies to the bottom selection.
Friday, September 07. 2018
LDC #101: Page Break Template Manager, Part 3
To do this, we need to add a function, toggle_buttons, and edit the modify_load and modify_action functions a bit. The toggle_buttons function is going to handle enabling / disabling buttons, the modify_load function needs to have code for new buttons. The modify_action function needs to actually handle our re-ordering buttons to make sure things are swapped around in the right order. Let’s start by looking at the new modify_load function.
/****************************************/ void modify_load(){ /* load options into the modify dialog */ /****************************************/ ... omitted variable declarations ... ControlChangeFont(ADJ_UP,"Wingding"); /* set wingdings */ ControlChangeFont(ADJ_DOWN,"Wingding"); /* set wingdings */ size = ArrayGetAxisDepth(page_breaks); /* get size of page breaks array */ selected = DataControlGetRowSelection(TEMPLATE_LIST); /* get the selected item from the list */ DataControlResetContent(TEMPLATE_LIST); /* reset contents of the dialog */ DataControlSetColumnHeadings(TEMPLATE_LIST,"Template Name"); /* set the heading for the data control */ DataControlSetColumnPositions(TEMPLATE_LIST, 267); /* set the width of the heading */ for(ix=0;ix<size;ix++){ /* for each page break */ if((page_breaks[ix][0]!=SYNTAX_TAG) && /* if it's not a part of the HTML syntax*/ (page_breaks[ix][0]!="")){ /* if it's not blank */ name = ReplaceInString(page_breaks[ix][0],P_START,""); /* strip out p start tag */ name = ReplaceInString(name,P_END,""); /* strip out p end tag */ DataControlInsertString(TEMPLATE_LIST,ix,name); /* add it to the dialog */ } /* */ } /* */ if (selected > 0){ /* if we had a selected value */ DataControlSetRowSelection(TEMPLATE_LIST,selected); /* reset the previous selection */ } /* */ } /* */
The two lines of the modify_load function handle setting the font of the buttons to wingdings. This causes the text to show up and down arrows. I wanted arrow buttons here, and this is the easiest way to achieve this. If you want to use more specific looking arrow buttons, you can always set images as your buttons instead, but using wingdings characters here made sense. Also added to this function was the line to get the selected value from the sheet before clearing it, and after we’ve reset the sheet and added all the items back, if we had a selection to begin with, we set the previously selected row back in. This makes our load function work as both an initial load and a “refresh” function, so we can call it after running a rename and not lose our current selection.
Our modify_action function is pretty heavily modified, so instead of just pointing out modified portions, let’s look at how the whole thing works.
/****************************************/ void modify_action(int c_id, int action){ /* action on the modify dialog */ /****************************************/ ... omitted variable declarations ... if(c_id != ADJ_UP && c_id!= ADJ_DOWN && c_id!=TEMPLATE_RENAME /* if it's not one of our buttons */ && c_id != TEMPLATE_DELETE && action != DCN_DOUBLE_CLICK){ /* or a double click */ return; /* */ } /* ` */ selected = DataControlGetRowSelection(TEMPLATE_LIST); /* get the selected item from the list */ data = DataControlGetTable(TEMPLATE_LIST); /* get the data from the list */ toggle_buttons(selected,ArrayGetAxisDepth(data)); /* toggle buttons off and on */ if (selected <0){ /* if we have no selection */ return; /* nothing to do */ } /* */ if (c_id == TEMPLATE_LIST && action == DCN_DOUBLE_CLICK){ /* if user double clicked a list item */ c_id = TEMPLATE_RENAME; /* do same thing as if user did rename */ } /* */
The modify_action function starts off by testing to see if the control calling it is one of our buttons, or if it’s a double click action. If it’s not any of these, then it can just return, because there’s nothing to do here. We need to do this because this function is called whenever a user does anything on the dialog, including moving the mouse. If it’s called repeatedly, we need to make sure it’s extremely fast to exit if it doesn’t have to do anything. Then, we can get the selected value and the data table, and running the toggle_buttons function to ensure the available buttons are appropriate for whatever was selected. If there wasn’t a selected value, we can just return here, because there’s nothing else to do. If the control was the TEMPLATE_LIST, and the user double-clicked on it, we can just treat it as though the user pressed the Rename button, so we can change the control id variable c_id to the TEMPLATE_RENAME value, so we can just act like we’re renaming the template.
selected_nm = TrimPadding(data[selected][0]); /* get the name of the selected row */ selected_fn = FormatString(P_TEMPLATE,selected_nm); /* get full name of renaming template */ selected_id = -1; /* init renaming ID to -1 */ size = ArrayGetAxisDepth(page_breaks); /* get size of page break table */ for(ix=0;ix<size;ix++){ /* for each row in table */ if (selected_fn == TrimPadding(page_breaks[ix][0])){ /* if name matches the row in the db */ selected_id = ix; /* store ID for later */ break; /* break loop */ } /* */ } /* */
This section of code is copied from the previous version of this function. We need to get the selected template name, format it with our paragraph tags to wrap around it, and then find it in our page breaks array, to get the row number of our selection in the underlying data structure, page_breaks.
if (c_id == ADJ_UP || c_id == ADJ_DOWN){ /* if adjusting the list order */ modified = true; /* flag file as modified */ if (c_id == ADJ_UP){ /* if up button pressed */ dir = -1; /* set direction to move up in list */ } /* */ if (c_id == ADJ_DOWN){ /* if down button pressed */ dir = 1; /* set direction to move down in list */ } /* */ DataControlSwapRows(TEMPLATE_LIST,selected,selected+dir); /* swap row up in list */ DataControlSetRowSelection(TEMPLATE_LIST,selected+dir); /* set the selection */ selected = selected+dir; /* change selection variable */ temp = page_breaks[selected_id]; /* store selection */ page_breaks[selected_id] = page_breaks[selected_id+dir]; /* swap rows */ page_breaks[selected_id+dir] = temp; /* swap rows */ toggle_buttons(selected,ArrayGetAxisDepth(data)); /* toggle buttons off and on */ } /* */
If the user has pressed the ADJ_UP or ADJ_DOWN buttons (our new re-order up or down buttons), then we need to set the direction we’re moving in to either 1 or -1 depending on the button pressed. We can then use the DataControlSwapRows and DataControlSetRowSelection functions to swap our selected row either up or down one, and move our selection onto our new row position. This just changes the display though, so we need to change our data structure that actually holds the page breaks as well, so we can use our temp variable temp to hold our selected row’s value, then swap the value that was previously at the position we’re moving to with our selected value.
if (c_id == TEMPLATE_RENAME){ /* if rename was pressed */ rc = rename(selected_nm); /* run the rename function */ if (IsError(rc)==false){ /* if rename didn't return an error */ modify_load(); /* reload the list */ } /* */ return; /* return */ } /* */ if (c_id == TEMPLATE_DELETE){ /* if delete was pressed */ rc = delete(selected_nm); /* run the delete function */ if (IsError(rc)==false){ /* if delete didn't return an error */ DataControlSetRowSelection(TEMPLATE_LIST,-1); /* reset selection */ selected = -1; /* reset selected variable */ modify_load(); /* reload the list */ toggle_buttons(selected,ArrayGetAxisDepth(data)); /* toggle buttons off and on */ } /* */ return; /* return */ } /* */ } /* */
The last two if statements in this function cover what to do if Rename or Delete buttons are pressed. This is pretty similar to what we had last week, but with some slight differences. Now that our load_modify function restores our last selected value whenever we call it, the Delete button needs to set the selected value to -1 to drop the selection, so that when our list reloads it doesn’t automatically select whatever is now in the position that was previously occupied by our deleted row. We also need to call toggle_buttons, so that it disables all of our dialog buttons until the user selects something else.
/****************************************/ void toggle_buttons(int selected, int size){ /* enables or disables buttons */ /****************************************/ if (selected <0){ /* if nothing is selected */ ControlDisable(ADJ_DOWN); /* disable the down button */ ControlDisable(ADJ_UP); /* disable the up button */ ControlDisable(TEMPLATE_RENAME); /* disable the template rename */ ControlDisable(TEMPLATE_DELETE); /* disable template delete */ return; /* return, nothing else to do */ } /* */ else{ /* if we have a selection */ ControlEnable(ADJ_DOWN); /* enable the down button */ ControlEnable(ADJ_UP); /* enable the up button */ if (selected == 0){ /* if first item is selected */ ControlDisable(ADJ_UP); /* disable the up button */ } /* */ if (selected == size-1){ /* if last item is selected */ ControlDisable(ADJ_DOWN); /* disable the down button */ } /* */ ControlEnable(TEMPLATE_RENAME); /* enable the control */ ControlEnable(TEMPLATE_DELETE); /* enable the control */ } /* */ } /* */
The toggle_buttons function takes our selected value and the size of the selected array as parameters, and enables or disables buttons based on those values. If nothing is selected, then we can just run ControlDisable to disable all of our buttons, and return, because we’re done. Otherwise, we can enable our up and down buttons, then check to see if they should actually be enabled. If selected is 0, then we’ve selected the first item, so ADJ_UP should be disabled. If the selected value equals the last row, then we need to disable ADJ_DOWN since you can’t press down anymore. Finally we can enable our delete and rename buttons, since the user has selected something.
With these changes, we’ve got a pretty useful little script now. We can save page breaks from our HTML file into a template, and we can go into a manager to rename, delete, or re-order that template file around however we want it. There are more things we could do to make this even fancier and more useful (like an edit button that would open the selected template in an edit window) we always need to keep in mind how long it would take to create that functionality, compared to how much time it would really save. I think where the script is at now is a pretty good balance of useful and quick to write, so this is a good place to leave it.
Here’s the complete script file, with all changes made:
/* PageBreakTemplateManager.ms * * Author: Steven Horowitz * * Notes: Allows a user to save and edit page break templates. */ /************************************************/ /* Defined Error / Warning Messages */ /************************************************/ #define TEMPLATE_FILENAME "HeaderFooterList.htm" #define P_TEMPLATE "<P STYLE=\"margin: 0\">{%s}</P>" #define SYNTAX_TAG "HTML_TAG_NOT_TITLE" #define P_START "<P STYLE=\"margin: 0\">{" #define P_END "}</P>" #define END_TABLE "</TABLE>" #define END_P_NAME "end" #define TEMPLATE_HTTP_LOC "http://www.novaworkssoftware.com/files/HeaderFooterList.htm" #define TEMPLATE_BODY_LINE "<BODY STYLE=\"font: 11pt Times New Roman, Times, Serif\">" #define TEST_X 0 #define TEST_Y 10 #define TEST_SAVE false #define TEST_MODIFY true /************************************************/ /* Function Signatures */ /************************************************/ void setup(); /* set up the hooks */ int run_save(int f_id, string mode, handle window); /* run the save template script */ int run_modify(int f_id, string mode); /* run the modify template script */ void modify_load(); /* load the modify dialog */ int save_validate(); /* validate if we can save a page break name */ int read_page_breaks(string filename); /* read the page breaks from a given file */ int save_page_breaks(string filename); /* save the page breaks to a given file */ int rename(string selected); /* rename a template */ int delete(string selected); /* delete a template */ int check_template_folder(); /* checks to make sure the template file exists */ void toggle_buttons(int selected, int size); /* enable / disable buttons based on selection */ /* */ /************************************************/ /* global values */ /************************************************/ string table_code; /* code for a table being saved */ string page_breaks[][]; /* array of all page break text */ boolean modified; /* true if we modify the page break template */ string renaming; /* the template we're currently renaming */ int selected_id; /* the id of the template w're renaming */ /****************************************/ void setup() { /* Called from Application Startup */ /****************************************/ string fn; /* file name */ string item[10]; /* menu item array */ string settings; /* the settings file location */ /* */ item["Code"] = "SAVE_PAGE_BREAK"; /* set hook code */ item["Description"] ="Save the current table as page break preset.";/* set hook description */ item["MenuText"] = "Save Page Break Template"; /* set menu text */ item["Class"] = "DocumentExtension"; /* set class as document */ MenuAddFunction(item); /* add menu item to menu */ fn = GetScriptFilename(); /* get the filename of the script */ MenuSetHook("SAVE_PAGE_BREAK", fn, "run_save"); /* set the hook */ /* add modify function */ item["Code"] = "MODIFY_PAGE_BREAK"; /* set hook code */ item["Description"] ="Modify the Page Break Templates."; /* set hook description */ item["MenuText"] = "Modify Page Break Template"; /* set menu text */ item["Class"] = "DocumentExtension"; /* set class as document */ MenuAddFunction(item); /* add menu item to menu */ fn = GetScriptFilename(); /* get the filename of the script */ MenuSetHook("MODIFY_PAGE_BREAK", fn, "run_modify"); /* set the hook */ } /* */ /****************************************/ void main(){ /* main function */ /****************************************/ int ix; /* counter */ int size; /* number of open windows */ string filename; /* filename of a window */ string ext; /* extension of current filename */ string windows[][]; /* array of all available windows */ /* */ if(GetScriptParent()=="LegatoIDE"){ /* if we're in IDE mode */ if (TEST_MODIFY){ /* if we're testing modify */ run_modify(0,"preprocess"); /* run preprocess */ } /* */ if (TEST_SAVE){ /* if we're testing save */ windows = EnumerateEditWindows(); /* get all active edit windows */ size = ArrayGetAxisDepth(windows); /* get the number of open windows */ for(ix=0;ix<size;ix++){ /* for each open edit window */ filename = windows[ix]["Filename"]; /* get the filename of the window open */ ext = GetExtension(filename); /* get the extension to the filename */ if (ext == ".htm"){ /* if the extension is HTML */ MessageBox("running save on file %s",filename); /* display running save */ run_save(0,"preprocess", /* run the save function */ MakeHandle(windows[ix]["ClientHandle"])); /* run the save function on the window */ } /* */ } /* */ } /* */ } /* */ setup(); /* run setup */ } /* */ /****************************************/ int run_modify(int f_id, string mode){ /* run the modify function */ /****************************************/ string template_file; /* the template file */ int rc; /* return code */ /* */ if (mode!="preprocess"){ /* if not preprocess */ SetLastError(ERROR_NONE); /* set the last error */ return ERROR_EXIT; /* return */ } /* */ selected_id = -1; /* unset renaming id */ renaming = ""; /* reset renaming */ modified = false; /* reset modified */ rc = check_template_folder(); /* check the templates folder */ if (rc!=ERROR_NONE){ /* if we have an error */ return ERROR_EXIT; /* return error */ } /* */ template_file = GetApplicationDataFolder(); /* Get the appdata directory */ template_file = AddPaths(template_file,"Templates"); /* build path to templates folder */ template_file = AddPaths(template_file,TEMPLATE_FILENAME); /* set path to template file */ rc = read_page_breaks(template_file); /* read the page break template */ if (rc!=ERROR_NONE){ /* if we have an error */ SetLastError(rc); /* set the last error message */ return ERROR_EXIT; /* return error */ } /* */ rc = DialogBox(MANAGE_TEMPLATES_DLG, "modify_"); /* enter the save dialog */ SetLastError(rc); /* set the last error */ return ERROR_EXIT; /* return no error */ } /* */ /****************************************/ void modify_load(){ /* load options into the modify dialog */ /****************************************/ string names[]; /* list of names of page breaks */ string name; /* name of a page break */ int selected; /* previously selected value */ int ix; /* loop counter */ int nx; /* name counter */ int size; /* size of page break array */ /* */ ControlChangeFont(ADJ_UP,"Wingding"); /* set wingdings */ ControlChangeFont(ADJ_DOWN,"Wingding"); /* set wingdings */ ButtonSetText(ADJ_UP,"é"); /* set image icon */ ButtonSetText(ADJ_DOWN,"ê"); /* set image icon */ size = ArrayGetAxisDepth(page_breaks); /* get size of page breaks array */ selected = DataControlGetRowSelection(TEMPLATE_LIST); /* get the selected item from the list */ DataControlResetContent(TEMPLATE_LIST); /* reset contents of the dialog */ DataControlSetColumnHeadings(TEMPLATE_LIST,"Template Name"); /* set the heading for the data control */ DataControlSetColumnPositions(TEMPLATE_LIST, 267); /* set the width of the heading */ for(ix=0;ix<size;ix++){ /* for each page break */ if((page_breaks[ix][0]!=SYNTAX_TAG) && /* if it's not a part of the HTML syntax*/ (page_breaks[ix][0]!="")){ /* if it's not blank */ name = ReplaceInString(page_breaks[ix][0],P_START,""); /* strip out p start tag */ name = ReplaceInString(name,P_END,""); /* strip out p end tag */ DataControlInsertString(TEMPLATE_LIST,ix,name); /* add it to the dialog */ } /* */ } /* */ if (selected > 0){ /* if we had a selected value */ DataControlSetRowSelection(TEMPLATE_LIST,selected); /* reset the previous selection */ } /* */ } /* */ /****************************************/ void modify_ok(){ /* save changes to page breaks */ /****************************************/ string template_file; /* path to template file */ /* */ template_file = GetApplicationDataFolder(); /* Get the appdata directory */ template_file = AddPaths(template_file,"Templates"); /* build path to templates folder */ template_file = AddPaths(template_file,TEMPLATE_FILENAME); /* set path to template file */ if (modified == true){ /* if we changed anything */ save_page_breaks(template_file); /* save the page break template */ } /* */ } /* */ /****************************************/ void modify_action(int c_id, int action){ /* action on the modify dialog */ /****************************************/ string temp[]; /* temp array for data storage */ string selected_nm; /* selected name */ string selected_fn; /* selected full name */ int dir; /* direction we're moving the selection */ int size; /* size of page break table */ int ix; /* loop counter */ int selected; /* selected index value */ string data[][]; /* content of the dialog's list */ int rc; /* result code */ /* */ if(c_id != ADJ_UP && c_id!= ADJ_DOWN && c_id!=TEMPLATE_RENAME /* if it's not one of our buttons */ && c_id != TEMPLATE_DELETE && action != DCN_DOUBLE_CLICK){ /* or a double click */ return; /* */ } /* ` */ selected = DataControlGetRowSelection(TEMPLATE_LIST); /* get the selected item from the list */ data = DataControlGetTable(TEMPLATE_LIST); /* get the data from the list */ toggle_buttons(selected,ArrayGetAxisDepth(data)); /* toggle buttons off and on */ if (selected <0){ /* if we have no selection */ return; /* nothing to do */ } /* */ if (c_id == TEMPLATE_LIST && action == DCN_DOUBLE_CLICK){ /* if user double clicked a list item */ c_id = TEMPLATE_RENAME; /* do same thing as if user did rename */ } /* */ selected_nm = TrimPadding(data[selected][0]); /* get the name of the selected row */ selected_fn = FormatString(P_TEMPLATE,selected_nm); /* get full name of renaming template */ selected_id = -1; /* init renaming ID to -1 */ size = ArrayGetAxisDepth(page_breaks); /* get size of page break table */ for(ix=0;ix<size;ix++){ /* for each row in table */ if (selected_fn == TrimPadding(page_breaks[ix][0])){ /* if name matches the row in the db */ selected_id = ix; /* store ID for later */ break; /* break loop */ } /* */ } /* */ if (c_id == ADJ_UP || c_id == ADJ_DOWN){ /* if adjusting the list order */ modified = true; /* flag file as modified */ if (c_id == ADJ_UP){ /* if up button pressed */ dir = -1; /* set direction to move up in list */ } /* */ if (c_id == ADJ_DOWN){ /* if down button pressed */ dir = 1; /* set direction to move down in list */ } /* */ DataControlSwapRows(TEMPLATE_LIST,selected,selected+dir); /* swap row up in list */ DataControlSetRowSelection(TEMPLATE_LIST,selected+dir); /* set the selection */ selected = selected+dir; /* change selection variable */ temp = page_breaks[selected_id]; /* store selection */ page_breaks[selected_id] = page_breaks[selected_id+dir]; /* swap rows */ page_breaks[selected_id+dir] = temp; /* swap rows */ toggle_buttons(selected,ArrayGetAxisDepth(data)); /* toggle buttons off and on */ } /* */ if (c_id == TEMPLATE_RENAME){ /* if rename was pressed */ rc = rename(selected_nm); /* run the rename function */ if (IsError(rc)==false){ /* if rename didn't return an error */ modify_load(); /* reload the list */ } /* */ return; /* return */ } /* */ if (c_id == TEMPLATE_DELETE){ /* if delete was pressed */ rc = delete(selected_nm); /* run the delete function */ if (IsError(rc)==false){ /* if delete didn't return an error */ DataControlSetRowSelection(TEMPLATE_LIST,-1); /* reset selection */ selected = -1; /* reset selected variable */ modify_load(); /* reload the list */ toggle_buttons(selected,ArrayGetAxisDepth(data)); /* toggle buttons off and on */ } /* */ return; /* return */ } /* */ } /* */ /****************************************/ void toggle_buttons(int selected, int size){ /* enables or disables buttons */ /****************************************/ if (selected <0){ /* if nothing is selected */ ControlDisable(ADJ_DOWN); /* disable the down button */ ControlDisable(ADJ_UP); /* disable the up button */ ControlDisable(TEMPLATE_RENAME); /* disable the template rename */ ControlDisable(TEMPLATE_DELETE); /* disable template delete */ return; /* return, nothing else to do */ } /* */ else{ /* if we have a selection */ ControlEnable(ADJ_DOWN); /* enable the down button */ ControlEnable(ADJ_UP); /* enable the up button */ if (selected == 0){ /* if first item is selected */ ControlDisable(ADJ_UP); /* disable the up button */ } /* */ if (selected == size-1){ /* if last item is selected */ ControlDisable(ADJ_DOWN); /* disable the down button */ } /* */ ControlEnable(TEMPLATE_RENAME); /* enable the control */ ControlEnable(TEMPLATE_DELETE); /* enable the control */ } /* */ } /* */ /****************************************/ int rename(string selected){ /* rename selected template */ /****************************************/ string fullname; /* full original name of break */ int rc; /* return code */ int s_pos; /* selected row position */ /* */ renaming = TrimPadding(selected); /* save the page break we're renaming */ rc = DialogBox(PAGEBREAK_TEMPLATES, "rename_"); /* enter the rename dialog */ return ERROR_NONE; /* return no error */ } /* */ /****************************************/ int delete(string selected){ /* delete selected template */ /****************************************/ int rc; /* return code */ /* */ rc= YesNoBox('q',"This will delete '%s', do you want to continue?", /* ask user if they want to delete */ selected); /* ask user to delete */ if (rc==IDYES){ /* if user pressed yes */ page_breaks[selected_id][0] = ""; /* delete page break */ page_breaks[selected_id][1] = ""; /* delete page break */ modified = true; /* set modified flag */ } /* */ return ERROR_NONE; /* */ } /* */ /****************************************/ int rename_load(){ /* load the rename dialog */ /****************************************/ EditSetText(TEMPLATE_NAME,renaming); /* load name of what we're renaming */ } /* */ /****************************************/ int rename_validate(){ /* validate the save name dialog */ /****************************************/ return save_validate(); /* alias to save_validate */ } /* */ /****************************************/ int rename_ok(){ /* process the rename */ /****************************************/ string newname; /* new name of page break */ /* */ if (selected_id>=0){ /* if we're renaming something */ newname = TrimPadding(EditGetText(TEMPLATE_NAME)); /* get the base new name */ newname = FormatString(P_TEMPLATE,newname)+"\r\n"; /* get full new name */ if (page_breaks[selected_id][0] != newname){ /* if we're actually modifying the name */ page_breaks[selected_id][0]=newname; /* set new name */ modified = true; /* set modified flag */ } /* */ modify_load(); /* reload modify dialog */ } /* */ } /* */ /****************************************/ int read_page_breaks(string filename){ /* read the page breaks */ /****************************************/ handle file; /* handle to template file */ handle wp; /* word parser object */ string line; /* individual line from template */ string next_word; /* next word in word parser */ string content; /* the content of the page break */ boolean in_break; /* true if in a page break */ int size; /* number of lines in file */ int ix; /* line counter */ int px; /* page counter */ int rc; /* return code */ /* */ file = OpenMappedTextFile(filename); /* open the template file */ rc = GetLastError(); /* get the last error */ if (IsError(rc)){ /* if we couldn't open the file */ MessageBox('x',"Cannot open template file."); /* display error message */ return ERROR_EXIT; /* return error */ } /* */ size = GetLineCount(file); /* get number of lines in file */ wp = WordParseCreate(WP_SGML_TAG); /* create word parser */ while (ix<size){ /* for each line in file */ line = ReadLine(file,ix); /* read a line from the file */ if (in_break){ /* if we're in a page break */ if (line!=""){ /* if the line has text */ content+=line+"\r\n"; /* add the line to the content */ } /* */ if (FindInString(line,END_TABLE)>=0){ /* if line has a close table */ in_break = false; /* we're not in a page break anymore */ page_breaks[px][1] = content+"\r\n"; /* store the page break in array */ content = ""; /* reset content variable */ px++; /* increment page counter */ } /* */ } /* */ else{ /* if we're not in a page break */ if (FindInString(line,P_START)==0){ /* if line starts with paragraph */ if (FindInString(line,FormatString("{%s}",END_P_NAME))>0){ /* if the paragraph is an end para */ page_breaks[px][0] = SYNTAX_TAG; /* set title to keyword */ page_breaks[px][1] = line+"\r\n"; /* store content of line */ px++; /* increment page break counter */ } /* */ else{ /* if it's not the end para */ in_break = true; /* we're now in a page break */ page_breaks[px][0] = line+"\r\n"; /* get the title */ } /* */ } /* */ else{ /* if we're not starting a page break */ if (line!=""){ /* if the line isn't blank */ page_breaks[px][0] = SYNTAX_TAG; /* set title to keyword */ page_breaks[px][1] = line+"\r\n"; /* store content of line */ px++; /* increment page break counter */ } /* */ } /* */ } /* */ ix++; /* increment counter */ } /* */ CloseHandle(wp); /* close the word parser */ CloseHandle(file); /* close the open file */ return ERROR_NONE; /* return without error */ } /* */ /****************************************/ int save_page_breaks(string filename){ /* save the page breaks to given file */ /****************************************/ handle file; /* the output file */ int rc; /* return code */ int size; /* size of page break array */ int ix; /* counter */ /* */ file = PoolCreate(); /* create a new mapped text file */ rc = GetLastError(); /* */ if (IsError(rc)){ /* if there is an error */ SetLastError(rc); /* set the error code */ return ERROR_EXIT; /* return an error */ } /* */ size = ArrayGetAxisDepth(page_breaks); /* get size of page break array */ for(ix=0;ix<size;ix++){ /* for each page break */ if(page_breaks[ix][0]!=""){ /* if there's something in this row */ if (page_breaks[ix][0]!=SYNTAX_TAG){ /* if it's not just part of template */ PoolAppend(file,page_breaks[ix][0]); /* write the title of the page break */ PoolAppend(file,"\r\n"); /* write a blank line */ } /* */ PoolAppend(file,page_breaks[ix][1]); /* write the content */ } /* */ } /* */ PoolWriteFile(file,filename); /* write output */ CloseHandle(file); /* close handle to the file */ return ERROR_NONE; /* return no error */ } /* */ /****************************************/ int check_template_folder(){ /* ensure the templates folder exists */ /****************************************/ int rc; /* return code */ string template_folder; /* the template folder */ string template_file; /* the template file */ /* */ template_folder = GetApplicationDataFolder(); /* Get the appdata directory */ template_folder = AddPaths(template_folder,"Templates"); /* build path to templates folder */ if (IsFolder(template_folder)==false){ /* if template folder doesn't exist */ rc = CreateFolder(template_folder); /* create the template folder */ if (IsError(rc)){ /* if we cannot create the folder */ MessageBox('x',"Cannot create template folder, error %0x",rc); /* display error */ return rc; /* return error code */ } } /* */ template_file = AddPaths(template_folder,TEMPLATE_FILENAME); /* set path to template file */ if (IsFile(template_file)==false){ /* if template file doesn't exist */ rc = HTTPGetFile(TEMPLATE_HTTP_LOC,template_file); /* get the template file */ if (IsError(rc)){ /* if we couldn't get the template */ MessageBox('x',"Cannot get template file, error %0x",rc); /* display error */ return rc; /* return with error */ } /* */ } /* */ return ERROR_NONE; /* return no error */ } /****************************************/ int run_save(int f_id, string mode, handle window){ /* run the save function */ /****************************************/ int rc; /* return code */ dword window_type; /* get the edit window type */ handle edit_object; /* handle to the edit object */ int caret[]; /* caret positions */ string template_file; /* the template file path */ string tag; /* full text of element tag */ string element; /* the current element */ handle sgml; /* handle to the SGML parser */ /* */ if (mode != "preprocess"){ /* if not preprocess */ SetLastError(ERROR_NONE); /* set last error to nothing */ return ERROR_EXIT; /* bail out */ } /* */ if (IsWindowHandleValid(window)==false){ /* if we have no valid handle */ /* */ window = GetActiveEditWindow(); /* get the active edit window */ window_type = GetEditWindowType(window); /* get the edit window type */ window_type = window_type & EDX_TYPE_ID_MASK; /* mask file type */ if (window_type != EDX_TYPE_PSG_PAGE_VIEW){ /* if we're not in page view */ MessageBox('x',"This function must be used in page view."); /* display error */ return ERROR_EXIT; /* quit running */ } /* */ edit_object = GetEditObject(window); /* get edit object from window */ caret[0] = GetCaretXPosition(window); /* get the caret position in window */ caret[1] = GetCaretYPosition(window); /* get the caret position in window */ } /* */ else{ /* if we were passed a window */ edit_object = GetEditObject(window); /* get edit object from window */ caret[0] = TEST_X; /* set test position x */ caret[1] = TEST_Y; /* set test postion y */ } /* */ sgml = SGMLCreate(edit_object); /* get handle to SGML object */ SGMLSetPosition(sgml,caret[0],caret[1]); /* set position in SGML parser */ element = "init"; /* initialize element with a value */ while (element!="TABLE" && element!=""){ /* while element is not table and exists*/ tag = SGMLPreviousElement(sgml); /* get the previous SGML tag */ element = SGMLGetElementString(sgml); /* get the string value of the element */ } /* */ if (element == ""){ /* if the element is empty */ MessageBox('x',"This function must be run inside a table."); /* display message */ return ERROR_EXIT; /* quit running */ } /* */ table_code = SGMLFindClosingElement(sgml, /* get the code of the table */ SP_FCE_CODE_AS_IS | SP_FCE_INCLUDE_WRAPPER); /* get the code of the table */ template_file = GetApplicationDataFolder(); /* Get the appdata directory */ template_file = AddPaths(template_file,"Templates"); /* build path to templates folder */ template_file = AddPaths(template_file,TEMPLATE_FILENAME); /* set path to template file */ rc = read_page_breaks(template_file); /* read templates so we can validate */ if (rc!=ERROR_NONE){ /* if we cannot read the templates */ SetLastError(rc); /* set the error */ return ERROR_EXIT; /* return with error */ } /* */ rc = DialogBox(PAGEBREAK_TEMPLATES, "save_"); /* enter the save dialog */ SetLastError(rc); /* set last erorr */ return ERROR_EXIT; /* exit */ } /* */ /****************************************/ int save_validate(){ /* validate the save name dialog */ /****************************************/ string pb_name; /* the name of the page break save */ string renaming_fn; /* full name of the pb we're renaming */ string fullname; /* full name of the page break */ int size; /* size of table */ int n_pos; /* position of name in array */ int ix; /* loop counter */ /* */ pb_name = EditGetText(TEMPLATE_NAME); /* get the template name */ if (pb_name == ""){ /* if page break name is blank */ MessageBox('x',"Template must have a name."); /* display error */ return ERROR_EXIT; /* return error */ } /* */ renaming_fn = FormatString(P_TEMPLATE,renaming); /* get full name of renaming template */ fullname = FormatString(P_TEMPLATE,pb_name); /* get full name of entered template */ size = ArrayGetAxisDepth(page_breaks); /* get the size of the page break array */ n_pos = FindInTable(page_breaks,fullname,0,FIND_NO_CASE); /* check if name already exists */ if (n_pos >= 0 && fullname != renaming_fn){ /* if the name is found */ MessageBox('x',"Name already exists, cannot duplicate."); /* display error */ return ERROR_EXIT; /* return an error */ } /* */ return ERROR_NONE; /* return no error */ } /* */ /****************************************/ int save_ok(){ /* after validating the save dialog */ /****************************************/ int rc; /* return code */ int ix; /* iterator */ int size; /* size of the mapped text file */ string pb_name; /* page break name */ string line; /* content of line of mapped text file */ handle file; /* handle to the template file */ string template_file; /* the template file */ string template_folder; /* templates folder */ /* */ pb_name = EditGetText(TEMPLATE_NAME); /* get the page break template name */ rc = check_template_folder(); /* check the templates folder */ if (rc!=ERROR_NONE){ /* if we have an error */ return ERROR_EXIT; /* return error */ } /* */ template_file = GetApplicationDataFolder(); /* Get the appdata directory */ template_file = AddPaths(template_file,"Templates"); /* build path to templates folder */ template_file = AddPaths(template_file,TEMPLATE_FILENAME); /* set path to template file */ file = OpenMappedTextFile(template_file); /* open the mapped text file */ size = GetLineCount(file); /* get number of lines in mapped text */ while (line != TEMPLATE_BODY_LINE && ix<size){ /* while we haven't found the body */ line = ReadLine(file,ix); /* get the line */ ix++; /* increment line counter */ } /* */ if (line!=TEMPLATE_BODY_LINE){ /* if we couldn't find the body */ MessageBox('x',"Template file is not valid."); /* display an error message */ return ERROR_EXIT; /* return error */ } /* */ line = FormatString(P_TEMPLATE,pb_name); /* build line to insert */ line+= "\r\n\r\n"+table_code+"\r\n"; /* build line to insert */ InsertLine(file,ix,line); /* insert line */ MappedTextSave(file); /* save our modified file */ rc = GetLastError(); /* get the last error */ if (IsError(rc)){ /* if we can't save */ MessageBox('x',"Cannot save template file."); /* display an error */ return ERROR_EXIT; /* return an error */ } /* */ return ERROR_NONE; /* return no error */ } /* */ /************************************************/ /* dialog controls */ /************************************************/ #beginresource /****************************************/ /* save template dialog */ /****************************************/ #define PAGEBREAK_TEMPLATES 101 #define TEMPLATE_PROPERTIES 102 #define TEMPLATE_NAME 103 PAGEBREAK_TEMPLATES DIALOGEX 0, 0, 240, 66 EXSTYLE WS_EX_DLGMODALFRAME STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Header / Footer Properties" FONT 8, "MS Sans Serif" { CONTROL "OK", IDOK, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 132, 50, 50, 14 CONTROL "Cancel", IDCANCEL, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 187, 50, 50, 14 CONTROL "Name:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 14, 25, 40, 13, 0 CONTROL "Template Properties:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 10, 8, 86, 13, 0 CONTROL "Frame1", -1, "static", SS_ETCHEDFRAME | WS_CHILD | WS_VISIBLE, 84, 12, 146, 1, 0 CONTROL "", TEMPLATE_NAME, "edit", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL, 53, 25, 172, 12, 0 } #define MANAGE_TEMPLATES_DLG 200 #define TEMPLATE_LIST 201 #define TEMPLATE_DELETE 202 #define TEMPLATE_RENAME 203 #define ADJ_UP 204 #define ADJ_DOWN 205 MANAGE_TEMPLATES_DLG DIALOGEX 0, 0, 364, 143 EXSTYLE WS_EX_DLGMODALFRAME STYLE DS_3DLOOK | DS_MODALFRAME | DS_SETFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU CAPTION "Manage Preference Templates" FONT 8, "MS Shell Dlg" { CONTROL "", TEMPLATE_LIST, "data_control", 0x50A10003, 33, 6, 267, 106, 0x00000000 CONTROL "é &U", ADJ_UP, "button", BS_PUSHBUTTON | BS_LEFT | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 10, 26, 11, 12, 0 CONTROL "ê &D", ADJ_DOWN, "button", BS_PUSHBUTTON | BS_LEFT | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 10, 50, 11, 12, 0 CONTROL "&Delete", TEMPLATE_DELETE, "button", BS_CENTER, 303, 7, 50, 14, WS_EX_LEFT CONTROL "&Rename", TEMPLATE_RENAME, "button", BS_CENTER, 303, 24, 50, 14, WS_EX_LEFT CONTROL "", -1, "static", SS_ETCHEDFRAME, 6, 218, 234, 1, WS_EX_LEFT CONTROL "Save", IDOK, "button", BS_PUSHBUTTON |BS_CENTER, 247, 123, 50, 14, WS_EX_LEFT CONTROL "Cancel", IDCANCEL, "button", BS_PUSHBUTTON |BS_CENTER, 303, 123, 50, 14, WS_EX_LEFT } #endresource
Steven Horowitz has been working for Novaworks for over five years as a technical expert with a focus on EDGAR HTML and XBRL. Since the creation of the Legato language in 2015, Steven has been developing scripts to improve the GoFiler user experience. He is currently working toward a Bachelor of Sciences in Software Engineering at RIT and MCC. |
Additional Resources
Legato Script Developers LinkedIn Group
Primer: An Introduction to Legato