• Solutions
    • FERC XBRL Reporting
    • FDTA Financial Reporting
    • SEC Compliance
    • Windows Clipboard Management
    • Legato Scripting
  • Products
    • GoFiler Suite
    • XBRLworks
    • SEC Exhibit Explorer
    • SEC Extractor
    • Clipboard Scout
    • Legato
  • Education
    • Training
    • SEC and EDGAR Compliance
    • Legato Developers
  • Blog
  • Support
  • Skip to blog entries
  • Skip to archive page
  • Skip to right sidebar

Friday, September 14. 2018

LDC #102: Dialog Boxes Part V — Introduction to the Data Control

Sometimes it is desirable to display tables of information and allow user to edit the data on the sheet directly. Novaworks’ products employ a table data editing platform that in many ways operates like MS Excel™ and provides a high level of flexibility. It is used for XBRL editing, EDGAR Forms, and much more. In this article, I will introduce the data control.


Introduction


The data control was originally designed to support EDGAR forms and XBRL editing with a high level of programmability. Overtime, control development has led to four distinct classes of operation:


Hierarchy of Data Controls in Legato 


The lowest level of the editing tools is the Data Sheet class. This class is accessible from Legato as the Data Sheet Object. It provides a sheet matrix supporting primary as well as meta data for each cell.


The next level is the Data Control. It can be directly used as a dialog control by using the class name “data_control”. It is incorporated within in the next two classes. The data control is what visualizes the data sheet and allows for basic editing.


Incorporating one or more Data Controls is Data View. Data View provides a spreadsheet-like interface that is used to support XBRL, EDGAR Forms, and much more. It incorporates sheet management (tabs as a complete workbook), editing and other processing. XBRL View directly incorporates Data View to control facts, contexts, elements and presentations.


Finally, Forms View incorporates Data View and provides for controlled level event-driven access to allow scripts to be written to create any type of data editing platform.


Within Legato, one might notice an overlap of many functions across these classes or objects. For example, the Data Sheet, Data Control and Data View objects all allow cell data to be referenced by name. Except for high level edit control for features such as undo, the API functions are identical.


Our focus will be to introduce the data control. The default setup for data control is to emulate the Windows list box class with a significant expansion of functionality. Let’s start with looking at the structure of the data.


The Matrix


For a list box, we have essentially a one column table. Windows list boxes allow for pseudo columns, but the implementation is very limited. Essentially pseudo columns are created in the single column with tab characters. If a synthetic cell gets too big, it will push the remaining data past the tab stop.


Data control takes a spreadsheet approach:


Description of Data Sheet


Each cell is an independent unit visually constrained by the optical dimensions of the columns and rows (or multiple columns if cells are merged). Data can be accessed cell by cell or like a list box in rows.


Each cell has many properties. We will cover those in a later article. For this article, we will treat cells as simple UTF text.


Data Control on a Dialog


For our example, I created a small script that loads a CSV file. For the data I picked a list of the top selling albums. With this, we can also demonstrate some of the display features:


Dialog showing data control with headings and selection


The dialog appears in three sections: the list, the details and a test area to show some of what is going on behind the scenes with a menu to run some data control functions.


By default, a data control will behave like a list box, with single row selection as shown above. However, unlike a list box, the select mode can be changed to individual cells. Also, you will notice that the fields, such as ‘Producer’, are too large, but they do not upset the column layout. In addition, a column legend has been added that is also active. It can be used to select a sorting method on a column and also the partitions can be dragged to expose or hide columns.


Here is the example code for our data control. Note that the CSV file must be downloaded or copied and saved (it is included below the code):


 


                                                                                ////////////////////////////////////////////////
                                                                                // Dialog

#beginresource

#define DC_DATA_CONTROL                         201
#define DC_YEAR                                 202
#define DC_SALES                                203
#define DC_ALBUM                                204
#define DC_ARTIST                               205
#define DC_PRODUCER                             206
#define DC_COMMENT                              207
#define DC_STATUS_DISPLAY                       208
#define DC_ACTION_DISPLAY                       209
#define DC_TESTS                                210


DataControlDlg DIALOGEX 0, 0, 400, 210
EXSTYLE WS_EX_DLGMODALFRAME
STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Data Control Example"
FONT 8, "MS Shell Dlg"
{
  CONTROL "", DC_DATA_CONTROL, "data_control", LBS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | WS_VSCROLL | WS_HSCROLL, 10, 10, 380, 110, 0
  CONTROL "Year:", -1, "static", WS_CHILD | WS_VISIBLE, 10, 126, 34, 8
  CONTROL "", DC_YEAR, "static", WS_CHILD | WS_VISIBLE, 45, 126, 20, 8
  CONTROL "Sales:", -1, "static", WS_CHILD | WS_VISIBLE, 95, 126, 34, 8
  CONTROL "", DC_SALES, "static", WS_CHILD | WS_VISIBLE, 130, 126, 70, 8
  CONTROL "Album:", -1, "static", WS_CHILD | WS_VISIBLE, 200, 126, 34, 8
  CONTROL "", DC_ALBUM, "static", WS_CHILD | WS_VISIBLE, 236, 126, 150, 8
  CONTROL "Artist:", -1, "static", WS_CHILD | WS_VISIBLE, 10, 140, 34, 8
  CONTROL "", DC_ARTIST, "static", WS_CHILD | WS_VISIBLE, 45, 140, 100, 8
  CONTROL "Producer:", -1, "static", WS_CHILD | WS_VISIBLE, 200, 140, 34, 8
  CONTROL "", DC_PRODUCER, "static", WS_CHILD | WS_VISIBLE, 236, 140, 150, 8
  CONTROL "Comment:", -1, "static", WS_CHILD | WS_VISIBLE, 10, 154, 34, 8
  CONTROL "", DC_COMMENT, "static", WS_CHILD | WS_VISIBLE, 45, 154, 300, 16
  CONTROL "", -1, "static", SS_ETCHEDFRAME | WS_CHILD | WS_VISIBLE, 10, 176, 375, 1
  CONTROL "", DC_STATUS_DISPLAY, "static", WS_CHILD | WS_VISIBLE, 10, 185, 280, 8
  CONTROL "", DC_ACTION_DISPLAY, "static", WS_CHILD | WS_VISIBLE, 10, 195, 280, 8
  CONTROL "Tests >>", DC_TESTS, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 340, 185, 45, 12
  }

#endresource

                                                                                ////////////////////////////////////////////////
    void                dc_show_stats                           ();
    int                 dc_function                             (string);


    string              menu[200];
    int                 r_swap_pos;
    int                 h_rx, h_cx, h_x;

                                                                                ////////////////////////////////////////////////
                                                                                // Control
int main() {
    int                 ix;

    menu[ix++] = "Reset Sort";
    menu[ix++] = "Sort B Ascend";
    menu[ix++] = "Sort B Descend";
    menu[ix++] = "Get Sort Stats";
    menu[ix++] = "separator";
    menu[ix++] = "Swap Rows (0 ...)";
    menu[ix++] = "separator";
    menu[ix++] = "Select Color Default";
    menu[ix++] = "Select Color Odd";
    menu[ix++] = "Select Color Inactive";
    menu[ix++] = "separator";
    menu[ix++] = "Get Click Position";
    menu[ix++] = "separator";
    menu[ix++] = "Highlight Cell";
    menu[ix++] = "Highlight Row";
    menu[ix++] = "Highlight Off";
    menu[ix++] = "separator";
    menu[ix++] = "Make Bold (Cell B)";
    menu[ix++] = "Make Italic (Cell B)";
    menu[ix++] = "Make Bold/Italic (Cell B)";
    menu[ix++] = "Make Normal (Cell B)";
    menu[ix++] = "separator";
    menu[ix++] = "Enable (Cell B)";
    menu[ix++] = "Disable (Cell B)";
    menu[ix++] = "Hide (Cell B)";

    DialogBox("DataControlDlg", "dc_");

    return ERROR_NONE;
    }


                                                                                ////////////////////////////////////////////////
                                                                                // Dialog Load
int dc_load() {
    string              table[][];

    DataControlSetColumnPositions(DC_DATA_CONTROL, 23, 122, 150, 210, 270, 350);
    DataControlSetColumnHeadings(DC_DATA_CONTROL, "Year", "Album Name", "Sales", "Artist", "Producer", "Comment");
    DataControlSetColumnFlags(DC_DATA_CONTROL,  DS_CC_SORT, 
                                                DS_CC_SORT, 
                                                DS_CC_SORT_NUMBERS, 
                                                DS_CC_SORT, 
                                                DS_CC_SORT, 
                                                DS_CC_SORT);

    DataControlSetDefaultRowHeight(DC_DATA_CONTROL, 14);                        // Row Height
    DataControlSetSelectColor(DC_DATA_CONTROL, "#BAD3FC", "black");             // Select Color
    DataControlSetLegendColor(DC_DATA_CONTROL, "#BAD3FC", "black");             // Legend Colors

    table = CSVReadTable(GetScriptFolder() + "data_control a.csv");
    DataControlAddTable(DC_DATA_CONTROL, table);

    dc_show_stats();
   
    return ERROR_NONE;
    }

                                                                                ////////////////////////////////////////////////
                                                                                // Action
void dc_action(int id, int code) {
    int         rect[10];
    int         rc;
    
    if (id == DC_DATA_CONTROL) {
      if (code == DCN_SELECT_CHANGE) { 
        dc_show_stats(); 
        EditSetText(DC_ACTION_DISPLAY, "Select Change");
        }
      if (code == DCN_SORT_CHANGE) { 
        dc_show_stats(); 
        EditSetText(DC_ACTION_DISPLAY, "Sort Change");
        }
      return 0;
      }
    if (id == DC_TESTS) {
      EditSetText(DC_ACTION_DISPLAY, "");
      rect = ControlGetPosition(id);
      rc = MenuTrackAdHocPopup(menu, rect["right"], rect["top"]);
      if (rc < 0) { return 0; }
      dc_function(menu[rc]);
      }
    }

                                                                                ////////////////////////////////////////////////
                                                                                // Dialog Support
void dc_show_stats() {
    int                 pos[2];
    int                 rows, cols;
    int                 s_cx, s_mode;
    int                 sx;

    sx = DataControlGetRowSelection(DC_DATA_CONTROL);
    if (sx >= 0) {
      EditSetText(DC_YEAR, DataControlGetCellText(DC_DATA_CONTROL, sx, 0));
      EditSetText(DC_SALES, DataControlGetCellText(DC_DATA_CONTROL, sx, 2) + " million units");
      EditSetText(DC_ALBUM, DataControlGetCellText(DC_DATA_CONTROL, sx, 1));
      EditSetText(DC_ARTIST, DataControlGetCellText(DC_DATA_CONTROL, sx, 3));
      EditSetText(DC_PRODUCER, DataControlGetCellText(DC_DATA_CONTROL, sx, 4));
      EditSetText(DC_COMMENT, DataControlGetCellText(DC_DATA_CONTROL, sx, 5));
      }

    rows   = DataControlGetRowCount(DC_DATA_CONTROL);
    cols   = DataControlGetColumnCount(DC_DATA_CONTROL);
    pos    = DataControlGetCaretPosition(DC_DATA_CONTROL);
    s_cx   = DataControlGetSortColumn(DC_DATA_CONTROL);
    s_mode = DataControlGetSortMode(DC_DATA_CONTROL);

    EditSetText(DC_STATUS_DISPLAY, "Size: %d x %d   Pos:  %d:%d   Sort cx: %s mode: %d", rows, cols, pos["Row"], pos["Col"], s_cx, s_mode);
    }

                                                                                ////////////////////////////////////////////////
int dc_function(string name) {                                                  // Test a Function
    int                 pos[2];
    int                 rc;
    int                 s_cx, s_mode;

    if (name == "Reset Sort") {
      rc = DataControlSetSortColumn(DC_DATA_CONTROL);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetSortColumn returns 0x%08X", rc);
      return ERROR_NONE;
      }

    if (name == "Sort B Ascend") {
      rc = DataControlSetSortColumn(DC_DATA_CONTROL, 1);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetSortColumn returns 0x%08X", rc);
      return ERROR_NONE;
      }

    if (name == "Sort B Descend") {
      rc = DataControlSetSortColumn(DC_DATA_CONTROL, 1, 1);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetSortColumn returns 0x%08X", rc);
      return ERROR_NONE;
      }

    if (name == "Get Sort Stats") {
      s_cx   = DataControlGetSortColumn(DC_DATA_CONTROL);
      s_mode = DataControlGetSortMode(DC_DATA_CONTROL);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlGetSortColumn - Mode returns 0x%08X 0x%08X", s_cx, s_mode);
      return ERROR_NONE;
      }

    if (name == "Swap Rows (0 ...)") {
      rc = DataControlSwapRows(DC_DATA_CONTROL, r_swap_pos, r_swap_pos+1);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSwapRows returns 0x%08X (base %d)", rc, r_swap_pos);
      r_swap_pos++;
      return ERROR_NONE;
      }

    if (name == "Select Color Default") {
      rc = DataControlSetSelectColor(DC_DATA_CONTROL);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetSelectColor returns 0x%08X", rc);
      return ERROR_NONE;
      }

    if (name == "Select Color Odd") {
      rc = DataControlSetSelectColor(DC_DATA_CONTROL, "Purple");
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetSelectColor returns 0x%08X", rc);
      return ERROR_NONE;
      }

    if (name == "Select Color Inactive") {
      rc = DataControlSetSelectColor(DC_DATA_CONTROL, 0x00999999, 0x00111188, 0x00DDDDDD);
//    rc = DataControlSetSelectColor(DC_DATA_CONTROL, "#999", "#811", "#DDD");
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetSelectColor returns 0x%08X", rc);
      return ERROR_NONE;
      }

    if (name == "Get Click Position") {
      pos = DataControlGetClickPosition(DC_DATA_CONTROL);
      rc = GetLastError();
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlGetClickPosition row %d col %d  (0x%08X)", pos[0], pos[1], rc);
      return ERROR_NONE;
      }

    if (name == "Highlight Cell") {
      h_rx++; h_cx++; h_x++;
      rc = DataControlSetCellHighlight(DC_DATA_CONTROL, h_rx, h_cx, h_x);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetCellHighlight returns 0x%08X (%d:%d - x %d)", rc, h_rx, h_cx, h_x);
      return ERROR_NONE;
      }

    if (name == "Highlight Row") {
      h_rx++; h_cx++; h_x++;
      h_cx = -1;
      rc = DataControlSetCellHighlight(DC_DATA_CONTROL, h_rx, h_cx, h_x);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetCellHighlight returns 0x%08X (%d:%d - x %d)", rc, h_rx, h_cx, h_x);
      return ERROR_NONE;
      }

    if (name == "Highlight Off") {
      rc = DataControlSetHighlightMode(DC_DATA_CONTROL, FALSE);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetHighlightMode returns 0x%08X", rc);
      return ERROR_NONE;
      }

    if (name == "Make Bold (Cell B)") {
      rc = DataControlGetRowSelection(DC_DATA_CONTROL);
      if (rc < 0) {
        EditSetText(DC_ACTION_DISPLAY, "Need Selection");
        return ERROR_NONE;
        }
      rc = DataControlSetCellStyle(DC_DATA_CONTROL, rc, 1, TRUE);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetCellStyle returns 0x%08X", rc);
      return ERROR_NONE;
      }

    if (name == "Make Italic (Cell B)") {
      rc = DataControlGetRowSelection(DC_DATA_CONTROL);
      if (rc < 0) {
        EditSetText(DC_ACTION_DISPLAY, "Need Selection");
        return ERROR_NONE;
        }
      rc = DataControlSetCellStyle(DC_DATA_CONTROL, rc, 1, FALSE, TRUE);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetCellStyle returns 0x%08X", rc);
      return ERROR_NONE;
      }

    if (name == "Make Bold/Italic (Cell B)") {
      rc = DataControlGetRowSelection(DC_DATA_CONTROL);
      if (rc < 0) {
        EditSetText(DC_ACTION_DISPLAY, "Need Selection");
        return ERROR_NONE;
        }
      rc = DataControlSetCellStyle(DC_DATA_CONTROL, rc, 1, TRUE, TRUE);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetCellStyle returns 0x%08X", rc);
      return ERROR_NONE;
      }

    if (name == "Make Normal (Cell B)") {
      rc = DataControlGetRowSelection(DC_DATA_CONTROL);
      if (rc < 0) {
        EditSetText(DC_ACTION_DISPLAY, "Need Selection");
        return ERROR_NONE;
        }
      rc = DataControlSetCellStyle(DC_DATA_CONTROL, rc, 1);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetCellStyle returns 0x%08X", rc);
      return ERROR_NONE;
      }

    if (name == "Enable (Cell B)") {
      rc = DataControlGetRowSelection(DC_DATA_CONTROL);
      if (rc < 0) {
        EditSetText(DC_ACTION_DISPLAY, "Need Selection");
        return ERROR_NONE;
        }
      rc = DataControlSetCellState(DC_DATA_CONTROL, rc, 1, TRUE);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetCellState returns 0x%08X", rc);
      return ERROR_NONE;
      }

    if (name == "Disable (Cell B)") {
      rc = DataControlGetRowSelection(DC_DATA_CONTROL);
      if (rc < 0) {
        EditSetText(DC_ACTION_DISPLAY, "Need Selection");
        return ERROR_NONE;
        }
      rc = DataControlSetCellState(DC_DATA_CONTROL, rc, 1, FALSE);
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetCellState returns 0x%08X", rc);
      return ERROR_NONE;
      }

    if (name == "Hide (Cell B)") {
      rc = DataControlGetRowSelection(DC_DATA_CONTROL);
      if (rc < 0) {
        EditSetText(DC_ACTION_DISPLAY, "Need Selection");
        return ERROR_NONE;
        }
      rc = DataControlSetCellState(DC_DATA_CONTROL, rc, 1, (-1));
      dc_show_stats();
      EditSetText(DC_ACTION_DISPLAY, "DataControlSetCellState returns 0x%08X", rc);
      return ERROR_NONE;
      }

    return ERROR_NONE;
    }

The Sample CSV - “data_control a.csv”


"1982","Thriller","110","Michael Jackson","Michael Jackson, Quincy Jones","‘Thriller’ is the highest selling album of all-time, with numerous songs on the album going to #1."
"1980","Back in Black","49","AC/DC","Robert John “Mutt” Lange","With Brian Johnson taking over as the front man, this was the first AC/DC album after Bon Scott’s death."
"1973","Dark Side of the Moon","43","Pink Floyd","Pink Floyd","Though Syd Barrett was gone, this album stayed on Billboard for a record 14 consecutive years until 1988."
"1977","Bat out of Hell","43","Meat Loaf","Todd Rundgren","An appearance on ‘Saturday Night Live’ helped the album receive a huge following in the USA."
"1976","Their Greatest Hits 1971-1975","42","Eagles","Glyn Johns, Bill Szymczyk","This was the first album to reach ‘platinum’ status and is the highest selling album of all-time in the USA."
"1987","Dirty Dancing Soundtrack","42","Various Artists","Jimmy Ienner","Many of the oldies from the movie were inspired from film producer Eleanor Bergstein’s personal collection."
"1992","The Bodyguard Soundtrack","42","Whitney Houston, Various Artists","Whitney Houston, Clive Davis","Whitney Houston’s cover of Dolly Parton’s “I Will Always Love You” is the highlight of this soundtrack."
"1977","Rumours","40","Fleetwood Mac","Fleetwood Mac, Ken Caillat, Richard Dashut","The name of the album a reflection of band members writing about each other."
"1977","Saturday Night Fever Soundtrack","40","Bee Gees, Various Artists","Arif Mardin","With most recording done by the Bee Gees, this is the number one best-selling soundtrack of all-time."
"1999","Millennium","40","Backstreet Boys","Max Martin, Kristian Lundin","Debuting on Billboard at #1, Millennium sold almost half a million copies in the US on its first day."

The Dialog Resource


Let’s start by looking at the resource definition:


DataControlDlg DIALOGEX 0, 0, 400, 210
EXSTYLE WS_EX_DLGMODALFRAME
STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Data Control Example"
FONT 8, "MS Shell Dlg"
{
  CONTROL "", DC_DATA_CONTROL, "data_control", LBS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | WS_VSCROLL | WS_HSCROLL, 10, 10, 380, 110, 0
  CONTROL "Year:", -1, "static", WS_CHILD | WS_VISIBLE, 10, 126, 34, 8
  CONTROL "", DC_YEAR, "static", WS_CHILD | WS_VISIBLE, 45, 126, 20, 8
  CONTROL "Sales:", -1, "static", WS_CHILD | WS_VISIBLE, 95, 126, 34, 8
  CONTROL "", DC_SALES, "static", WS_CHILD | WS_VISIBLE, 130, 126, 70, 8
  CONTROL "Album:", -1, "static", WS_CHILD | WS_VISIBLE, 200, 126, 34, 8
  CONTROL "", DC_ALBUM, "static", WS_CHILD | WS_VISIBLE, 236, 126, 150, 8
  CONTROL "Artist:", -1, "static", WS_CHILD | WS_VISIBLE, 10, 140, 34, 8
  CONTROL "", DC_ARTIST, "static", WS_CHILD | WS_VISIBLE, 45, 140, 100, 8
  CONTROL "Producer:", -1, "static", WS_CHILD | WS_VISIBLE, 200, 140, 34, 8
  CONTROL "", DC_PRODUCER, "static", WS_CHILD | WS_VISIBLE, 236, 140, 150, 8
  CONTROL "Comment:", -1, "static", WS_CHILD | WS_VISIBLE, 10, 154, 34, 8
  CONTROL "", DC_COMMENT, "static", WS_CHILD | WS_VISIBLE, 45, 154, 300, 16
  CONTROL "", -1, "static", SS_ETCHEDFRAME | WS_CHILD | WS_VISIBLE, 10, 176, 375, 1
  CONTROL "", DC_STATUS_DISPLAY, "static", WS_CHILD | WS_VISIBLE, 10, 185, 280, 8
  CONTROL "", DC_ACTION_DISPLAY, "static", WS_CHILD | WS_VISIBLE, 10, 195, 280, 8
  CONTROL "Tests >>", DC_TESTS, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 340, 185, 45, 12
  }

The first control is the data control specified with the class name data_control. Note the use of the LBS_NOTIFY style. Data controls accept most list box styles. This style expands the number of messages send to the action procedure. The remainder of the definitions include mostly static class controls as text and one etched line. Then there is the ‘Test’ button. All of these control types have been discussed in my previous dialog articles. The only other style item worth mentioning is that the data control height is as specified. List boxes by default snap their height to an interval of the default row height.


Initialize and Load


The dc_load() function performs two basic functions: sets up the data control and loads the data control. If the setup here is not performed, the data control will appear more like a list box with the column position defaulting to a set interval.


int dc_load() {
    string              table[][];

    DataControlSetColumnPositions(DC_DATA_CONTROL, 23, 122, 150, 210, 270, 350);
    DataControlSetColumnHeadings(DC_DATA_CONTROL, "Year", "Album Name", "Sales", "Artist", "Producer", "Comment");
    DataControlSetColumnFlags(DC_DATA_CONTROL,  DS_CC_SORT, 
                                                DS_CC_SORT, 
                                                DS_CC_SORT_NUMBERS, 
                                                DS_CC_SORT, 
                                                DS_CC_SORT, 
                                                DS_CC_SORT);

    DataControlSetDefaultRowHeight(DC_DATA_CONTROL, 14);                        // Row Height
    DataControlSetSelectColor(DC_DATA_CONTROL, "#BAD3FC", "black");             // Select Color
    DataControlSetLegendColor(DC_DATA_CONTROL, "#BAD3FC", "black");             // Legend Colors

    table = CSVReadTable(GetScriptFolder() + "data_control a.csv");
    DataControlAddTable(DC_DATA_CONTROL, table);

    dc_show_stats();
   
    return ERROR_NONE;
    }

The first thing to review is setting up the columns. The DataControlSetColumnPositions SDK function operates just like the ListBoxSetTabPositions function. The control ID is specified and then a series of positions are provided. The positions are the right edge of the column. There is no easy way to determine the values other than guessing, testing, and adjusting. Future Legato updates may include an API function to retrieve the current column positions.


The next function used is the DataControlSetColumnHeadings function. Its operation is pretty obvious; it sets strings as the column captions. However, the column heading (also known as a legend) will not appear unless this function is executed. By default, each column is fixed with no additional functionality. The next function, the DataControlSetColumnFlags function, tells the control how to process clicks as well as some default style information for each column. Each column’s style information is specified with bits expressing desired behavior:


 Definition Bitwise Description 
 Operation     
  DS_CC_NO_RESIZE 0x00000001 User Cannot Resize 
  DS_CC_ALLOW_DRAG 0x00000002 User Can Drag and Drop Columns 
  DS_CC_ALLOW_SELECT 0x00000004 User Can Select 
  DS_CC_ALLOW_RENAME 0x00000008 User Can Rename 
  DS_CC_ALLOW_PRESS 0x00000010 User Can Press Button (sort) 
 Contents     
  DS_CC_DEFAULT_NAME 0x00000020 Default Name (A, B, C) 
 Select (Highlight)     
  DS_CC_HIGHLIGHT 0x00000080 Column is Highlighted (legend) 
 Column Text Align     
  DS_CC_TEXT_MODE_MASK 0x00000C00 Text Mode Mask (Left, Right, etc) 
  DS_CC_TEXT_DEFAULT 0x00000000 Default (Left Text) 
  DS_CC_TEXT_LEFT 0x00000400 Left Text 
  DS_CC_TEXT_CENTER 0x00000800 Center Text 
  DS_CC_TEXT_RIGHT 0x00000C00 Right Text 
 Protection     
  DS_CC_READ_ONLY 0x00001000 Column is Read-Only 
  DS_CC_PROTECTED 0x00002000 Column is Protected (password) 
 Sorting     
  DS_CC_SORT_TYPE_MASK 0x000F0000 Sort Type Mask 
  DS_CC_SORT_NONE 0x00000000 Sort Not Allowed 
  DS_CC_SORT_TEXT 0x00010000 Sort Text (w/ case sensitivity) 
  DS_CC_SORT_TEXT_NO_CASE 0x00020000 Sort Text (no case sensitivity) 
  DS_CC_SORT_TEXT_NUMERIC 0x00030000 Sort Text/Numbers (as File List) 
  DS_CC_SORT_NUMERIC 0x00040000 Sort Treat as Auto Number 
  DS_CC_SORT_DATE_AUTO 0x00050000 Sort Treat as Auto Date 
 Control     
  DS_CC_HIDDEN 0x00100000 Column is Hidden 
  DS_CC_DISABLED 0x00200000 Column is Disabled 
  DS_CC_SORT_MASK 0x00C00000 Column Sort Mask 
  DS_CC_SORT_ACTIVE 0x00400000 Column Sort is Active (only one) 
  DS_CC_SORT_DESCEND 0x00800000 Sort Descending/Ascending 
 Reserved     
  DS_CC_RESERVED 0xFF000000 Reserved (internal flags) 
 Caller Combinations     
  DS_CC_SORT 0x00020410 General Sort, Left Align 
  DS_CC_SORT_DATE 0x00050410 Date Sort, Left Align 
  DS_CC_SORT_FILES 0x00030410 Filename Sort, Left Align 
  DS_CC_SORT_NUMBERS 0x00040C10 Sort as Numeric, Right Align 
  DS_CC_SORT_RIGHT 0x00020C10 General Sort, Right Align 

We have each column heading flags set to sort the column on click with a minor difference on the Sales columns. This column has sort with the numeric option and right align.


How many columns are there? Well, each of the above functions can expand the number of columns. Also, if data is added that contains more columns than the current sheet, the sheet will also automatically expand.


The next group of functions set up style. The DataControlSetDefaultRowHeight function sets the default row height. The default is 16 pixels. Each row can have its own height which will override the default height, but exploring that is beyond the scope of this article. Next, we set some colors. The DataControlSetSelectColor and DataControlSetLegendColor functions override the default Windows theme color.


Finally, we put information into the control. For this example, we will load a string table, but first we have to load the table using the CSVReadTable function. If this function fails, the control will be empty. In a production/public environment, it would be advisable to load the data, check and display errors concerning the load process. Then we would construct the CSV list before loading its information to the control. For our purposes, we can be simpler. Our sniglet of code:


    table = CSVReadTable(GetScriptFolder() + "data_control a.csv");
    DataControlAddTable(DC_DATA_CONTROL, table);

There are other ways to add data including:


int = DataControlAddString ( int id, string data );


int = DataControlInsertString ( int id, int row, string data );


Both Add and Insert functions accept tabbed or CSV data for the row to be inserted. Individual cells can also be replaced.


int = DataControlSetCellText ( int id, int row, int column, string data );


There are many other available setup options, such as select mode, that we will cover in a later blog.


The Status Update


The last thing called during the load procedure is the dc_show_stats() routine, which updates the dialog based on conditions in the data control. This serves two purposes: we can load some detail in the lower section and then add some debug/test stuff to the bottom area. Obviously the latter would not be on the dialog for a normal implementation but is shown here are part of the function and class exploration.


void dc_show_stats() {
    int                 pos[2];
    int                 rows, cols;
    int                 s_cx, s_mode;
    int                 sx;

    sx = DataControlGetRowSelection(DC_DATA_CONTROL);
    if (sx >= 0) {
      EditSetText(DC_YEAR, DataControlGetCellText(DC_DATA_CONTROL, sx, 0));
      EditSetText(DC_SALES, DataControlGetCellText(DC_DATA_CONTROL, sx, 2) + " million units");
      EditSetText(DC_ALBUM, DataControlGetCellText(DC_DATA_CONTROL, sx, 1));
      EditSetText(DC_ARTIST, DataControlGetCellText(DC_DATA_CONTROL, sx, 3));
      EditSetText(DC_PRODUCER, DataControlGetCellText(DC_DATA_CONTROL, sx, 4));
      EditSetText(DC_COMMENT, DataControlGetCellText(DC_DATA_CONTROL, sx, 5));
      }

    rows   = DataControlGetRowCount(DC_DATA_CONTROL);
    cols   = DataControlGetColumnCount(DC_DATA_CONTROL);
    pos    = DataControlGetCaretPosition(DC_DATA_CONTROL);
    s_cx   = DataControlGetSortColumn(DC_DATA_CONTROL);
    s_mode = DataControlGetSortMode(DC_DATA_CONTROL);

    EditSetText(DC_STATUS_DISPLAY, "Size: %d x %d   Pos:  %d:%d   Sort cx: %s mode: %d", 
                                   rows, cols, pos["Row"], pos["Col"], s_cx, s_mode);
    }

The first section retrieves the last select position from the data control. Note that the DataControlGetRowSelection function only works in single row select mode. If the return select/row index is not -1, it means a row has been selected, in which case, one by one, we retrieve each cell on that row and place it on to the dialog page.


The latter part covers our exploration of functions. The first two are used frequently:


int = DataControlGetRowCount ( int id );


int = DataControlGetColumnCount ( int id );


Their operation is pretty obvious except the column count is always one on an empty control.


int [] = DataControlGetCaretPosition ( int id );


The DataControlGetCaretPosition function returns the position as an array with the key names “Row” and “Col”, or 0 and 1, respectively. The column and row position are always processed and returned even if the select mode is set to rows or columns. As the user clicks on a row, it must be over a specific column and as such the column position is also set.


There are a couple of options to retrieve and set sorting modes.


int = DataControlGetSortColumn ( int id );


int = DataControlGetSortMode ( int id );


int = DataControlSetSortColumn ( int id, int column, [int mode] );


The column being sorted can be retrieved as well as its sorting mode. The mode is either ascending or descending. Note that, when data is inserted or added to the list, the list is not resorted.


Playing with Commands


The menu contains a series of functions to illustrate how a number of data control functions operate. You can play with the menu items and code. In the Legato IDE, you can press F1 to look at the documentation for each function.


Conclusion


This blog covered the basics of setting up and loading a data control. In my next blog, I will explain editing and retrieving data. Have fun with the example. Remember as stated above you must have the script and the csv file saved in the same folder for the example to function.


 


Scott Theis is the President of Novaworks and the principal developer of the Legato scripting language. He has extensive expertise with EDGAR, HTML, XBRL, and other programming languages.

Additional Resources

Novaworks’ Legato Resources

Legato Script Developers LinkedIn Group

Primer: An Introduction to Legato 



Posted by
Scott Theis
in Development at 15:39
Trackbacks
Trackback specific URI for this entry

No Trackbacks

Comments
Display comments as (Linear | Threaded)
No comments
The author does not allow comments to this entry

Quicksearch

Categories

  • XML Accounting
  • XML AICPA News
  • XML FASB News
  • XML GASB News
  • XML IASB News
  • XML Development
  • XML Events
  • XML FERC
  • XML eForms News
  • XML FERC Filing Help
  • XML Filing Technology
  • XML Information Technology
  • XML Investor Education
  • XML MSRB
  • XML EMMA News
  • XML FDTA
  • XML MSRB Filing Help
  • XML Novaworks News
  • XML GoFiler Online Updates
  • XML GoFiler Updates
  • XML XBRLworks Updates
  • XML SEC
  • XML Corporation Finance
  • XML DERA
  • XML EDGAR News
  • XML Investment Management
  • XML SEC Filing Help
  • XML XBRL
  • XML Data Quality Committee
  • XML GRIP Taxonomy
  • XML IFRS Taxonomy
  • XML US GAAP Taxonomy

Calendar

Back May '25 Forward
Mo Tu We Th Fr Sa Su
Sunday, May 18. 2025
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Feeds

  • XML
Sign Up Now
Get SEC news articles and blog posts delivered monthly to your inbox!
Based on the s9y Bulletproof template framework

Compliance

  • FERC
  • EDGAR
  • EMMA

Software

  • GoFiler Suite
  • SEC Exhibit Explorer
  • SEC Extractor
  • XBRLworks
  • Legato Scripting

Company

  • About Novaworks
  • News
  • Site Map
  • Support

Follow Us:

  • LinkedIn
  • YouTube
  • RSS
  • Newsletter
  • © 2024 Novaworks, LLC
  • Privacy
  • Terms of Use
  • Trademarks and Patents
  • Contact Us