Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Scout/Tutorial/3.7/Minicrm/Write the first page"

< Scout‎ | Tutorial‎ | 3.7
(Create an Outline Service: Added a tipp regarding outline service organization)
m (Column Width)
(45 intermediate revisions by 6 users not shown)
Line 1: Line 1:
{{note|Scout Tutorial|This page belongs to the {{ScoutLink|Tutorial|Minicrm Step-by-Step|Minicrm Step-by-Step Tutorial}}. It explains how create your first page in your project and fill it with data from the database. You need to {{ScoutLink|Tutorial|Setup a SQL Service|connect a database to your application}} in order to continue.}}
+
{{ScoutPage|cat=Tutorial 3.7}}
 +
{{note|Scout Tutorial|This page belongs to the [[{{BASEPAGENAME}}_Step-by-Step|Minicrm Step-by-Step Tutorial]]. It explains how to create your first page in your project and fill it with data from the database. You need to [[{{BASEPAGENAME}}/Set up SQL Service|connect a database to your application]] in order to continue.}}
  
A typical Eclipse Scout application consists of multiple '''outlines'''. Think of it as a folder hierarchy. Each "folder" is called a '''page'''. These pages comes '''with nodes''' (a list of child pages) or '''with table''' (a table filled with rows of data from a data sources such as a database).  
+
A typical Eclipse Scout application consists of multiple '''outlines'''. Think of it as a folder hierarchy. Each "folder" is called a '''page'''. These pages come '''with nodes''' (a list of child pages) or '''with a table''' (a table filled with rows of data from a data source such as a database). The '''table''' has named '''columns'''. We need to create models for all of these.
 +
 
 +
If we want to fill the tables with data, we need to create a '''service''' on the server side. This service will get data from the database and return ''tabular data'': data arranged in rows and columns which we can use to fill the tables we created on the client side.
 +
 
 +
Once we have all that we're ready to [[{{BASEPAGENAME}}/Add_a_search_form|add a search form]] to our application.
  
 
== What are we talking about? ==
 
== What are we talking about? ==
  
When we talk about ''outlines'' and ''pages'', think of a simple application. In this tutorial we're creating a miniature CRM. Here's what it may have, using the Eclipse Scout terminology:
+
When we talk about ''outlines'' and ''pages'', think of a simple application. In this tutorial we're creating a miniature CRM. Here's what it may look like, using the Eclipse Scout terminology:
  
 
# one outline for companies and persons
 
# one outline for companies and persons
 
## the companies page shows a table with rows from the company table on the database
 
## the companies page shows a table with rows from the company table on the database
## the persons page shows a table with rows from the persons table on the database
+
## the persons page shows a table with rows from the person table on the database
 
## for every person there is a list of nodes naming all the child pages
 
## for every person there is a list of nodes naming all the child pages
# there may be other outlines for different tasks or topics such as campaigns
+
# there may be other outlines for different tasks or topics, such as marketing campaigns
  
[[Image:Scout Pages and Outlines.jpg]]
+
[[Image:Scout Pages and Outlines.jpg|900px]]
  
 
If you look at the diagram above, there are some interesting things to note.
 
If you look at the diagram above, there are some interesting things to note.
Line 21: Line 26:
 
# the title of a child page underneath a table is not shown -- by default the first visible column of the table replaces whatever the name was (in the example above "Catherine" replaces whatever the name of the Person Details Page was)
 
# the title of a child page underneath a table is not shown -- by default the first visible column of the table replaces whatever the name was (in the example above "Catherine" replaces whatever the name of the Person Details Page was)
  
In this tutorial our '''first page''' will be the '''company''' table page. The '''standard outline''' is a prerequesite for it, so we'll start there.
+
In this tutorial, our '''first page''' will be the '''company''' table page. The '''standard outline''' is a prerequisite, so we'll start there.
  
All of these structures are stricly client-side structures. The '''server''' couldn't care less how the various services it provides will get used. The only thing we need on the server side is '''a service that returns company data'''.
+
All of these structures are strictly client-side structures. The '''server''' couldn't care less about how the various services it provides will get used. The only thing we need on the server side is '''a service that returns tabular company data'''.
  
 
== Add an Outline first ==
 
== Add an Outline first ==
  
Since a page can only be contained within an Outline, you need to define the ''Outline'' first. Open the client node in Eclipse Scout and expand the tree until you get to the ''Desktop'' node. Do a right click on that node and choose ''New Outline...''.
+
Since a page can only be contained within an Outline, you need to define the ''Outline'' first. Open the client node in Eclipse Scout and expand the tree until you reach the ''Desktop'' node. Right-click on the node and choose the ''New Outline...'' menu.
  
 
[[Image:Newoutline.jpg|Newoutline.jpg]]
 
[[Image:Newoutline.jpg|Newoutline.jpg]]
Line 35: Line 40:
 
[[Image:Newoutlinewizard.jpg|Newoutlinewizard.jpg]]
 
[[Image:Newoutlinewizard.jpg|Newoutlinewizard.jpg]]
  
{{note|Multilingual Texts|If you type ''Standard'' into the name field, you'll see all sorts of texts in the language of your locale. If you're not sure whether the string you picked is the right one, you can right-click it and choose ''Modify Entry...'' from the context menu. This will show you the ''key'' and all the translations. If you're still not happy, just create a new multilingual text: type ''Standard'' into the name field and pick '''New translated text...''' from the list.}}
+
{{note|Multilingual Texts|If you type ''Standard'' into the name field, you'll see all sorts of texts in the language of your locale. If you're not sure whether the string you picked is the right one, you can right-click on it and choose ''Modify Entry...'' from the context menu. This will show you the ''key'' and all available translations. If you're still not happy, just create a new multilingual text: type ''Standard'' into the name field and pick '''New translated text...''' from the list.}}
  
If you expand the ''Desktop'', you should see the newly created ''StandardOutline''.
+
When you expand the ''Desktop'', you should see the newly created ''StandardOutline''.
  
 
[[Image:Standardoutline.jpg|Standardoutline.jpg]]
 
[[Image:Standardoutline.jpg|Standardoutline.jpg]]
  
{{note|Files Created|If you switch to the '''Java Perspective''' you can look at the file created: eclipse.org.minicrm.client.ui.desktop.outlines contains the new '''StandardOutline.java'''. If you see the key "SC_Label_UseDefaults" being used in the source code, then you might have picked a multilingual text you did not intend to. Go back to the '''StandardOutline''' in the ''Scout Perspective'' and modify the entry for the name as discussed above in the note on multilingual texts.}}
+
{{note|Files Created|If you switch to the '''Java Perspective''', you can have a look at the created files: Package <tt>eclipse.org.minicrm.client.ui.desktop.outlines</tt> contains the new '''StandardOutline.java''' class. If you see the key "SC_Label_UseDefaults" being used in the source code, then you might have picked a multilingual text you did not intend to. Go back to the '''StandardOutline''' in the ''Scout Perspective'' and modify the entry for the name as discussed above in the note on multilingual texts.}}
  
== Add a page to the Outline ==
+
== Add a Page to the Outline ==
  
Now you can add a new page to your StandardOutline. Right click on the ''Child Pages'' node of your ''StandardOutline'' and then choose ''New Page...''.
+
Now you can add a new page to your StandardOutline. Right-click on the ''Child Pages'' node of your ''StandardOutline'' and then choose ''New Page...''.
  
 
[[Image:Newpage.jpg|Newpage.jpg]]
 
[[Image:Newpage.jpg|Newpage.jpg]]
  
From the dropdown list choose '''AbstractPageWithTable''' then click next.
+
From the dropdown list choose '''AbstractPageWithTable''', then click next.
  
 
[[Image:Newtablepage.jpg|Newtablepage.jpg]]
 
[[Image:Newtablepage.jpg|Newtablepage.jpg]]
Line 55: Line 60:
 
Now enter the name for the new table page: ''Company''.
 
Now enter the name for the new table page: ''Company''.
  
If there is no appropriate multilingual text pick ''New translated text...'' from the list and provide a key and a default translation.
+
If there is no appropriate multilingual text, pick ''New translated text...'' from the list and provide a key and a default translation.
  
 
[[Image:Newtext.jpg|Newtext.jpg]]
 
[[Image:Newtext.jpg|Newtext.jpg]]
Line 61: Line 66:
 
[[Image:Companytext.jpg|Companytext.jpg]]
 
[[Image:Companytext.jpg|Companytext.jpg]]
  
{{note|Files Changed|Creating a new translated text will create an entry in '''Texts.java''' and appropriate property files: ''Texts.properties'' for the default language, ''Texts_de.properties'' for German, and so on). You can find these files in the ''Java Perpective'' under ''eclipse.org.minicrm.shared/resources/texts''.}}
+
{{note|Files Changed|Creating a new translated text will create entries in different property files: ''Texts.properties'' for the default language, ''Texts_de.properties'' for German, and so on). You can find these property files in the ''Java Perspective'' under ''eclipse.org.minicrm.shared/resources/texts''. }}
  
Eclipse Scout also comes with an editor to '''edit all the property files for multilingual texts''' in one go. If you expand the ''shared'' node in your Eclipse Scout project, activate ''Texts'' and click on <u>open nls editor</u> link in the Scout Object properties view, you can manage all your application's texts.
+
Eclipse Scout also comes with an editor to '''edit all the property files for multilingual texts''' in one go. If you expand the ''shared'' node in your Eclipse Scout project, activate ''Texts'' and click on the <u>open nls editor</u> link in the Scout Object properties view. Here you can conveniently manage all your application texts.
  
 
[[Image:Nls.jpg|Nls.jpg]]
 
[[Image:Nls.jpg|Nls.jpg]]
Line 71: Line 76:
 
[[Image:Companytablepage.jpg|Companytablepage.jpg]]
 
[[Image:Companytablepage.jpg|Companytablepage.jpg]]
  
When you expand now the ''Child Pages'' folder below your ''StandardOutline'', you'll find the new ''CompanyTablePage''. When you expand the node ''Table'', you'll find a folder ''Menus'' and ''Columns''. Below ''Columns'' we will now '''add the columns''' that are needed to display the company data.
+
When you now expand the ''Child Pages'' folder below your ''StandardOutline'', you'll find the new ''CompanyTablePage''. When you expand the node ''Table'', you'll find a folder ''Menus'' and ''Columns''. Below ''Columns'' we will now '''add the columns''' that are needed to display the company data.
  
 
[[Image:Finishedcompanytablepage.jpg|Finishedcompanytablepage.jpg]]
 
[[Image:Finishedcompanytablepage.jpg|Finishedcompanytablepage.jpg]]
Line 79: Line 84:
 
== Add colums to the table ==  
 
== Add colums to the table ==  
  
The next step is '''adding columns to the table'''. Add a column for the primary key (''CompanyNrColumn''), one for the company's shortname (''ShortNameColumn'') and one for the company's name (''NameColumn'').
+
The next step is '''adding columns to the table'''. Add a column for the primary key (''CompanyNrColumn''), one for the company's short name (''ShortNameColumn'') and one for the company's name (''NameColumn'').
  
 
The context menu for creating a new table column is on the ''Columns'' node right below the page's table.
 
The context menu for creating a new table column is on the ''Columns'' node right below the page's table.
Line 85: Line 90:
 
[[Image:Newcolumn.jpg|Newcolumn.jpg]]
 
[[Image:Newcolumn.jpg|Newcolumn.jpg]]
  
First, you have to choose a '''template''' for your column. The template used depends on the '''data type''' of your data and the '''format''' you want to use when displaying it. Eclipse Scout will attempt to cast your data types appropriately.
+
First you have to choose a '''template''' for your column. The template used depends on the '''data type''' of your data and the '''format''' you want to use when displaying it. Eclipse Scout will attempt to cast your data types appropriately.
  
 
Choose ''Long Column'' for the first column and ''String Column'' for the remaining columns.
 
Choose ''Long Column'' for the first column and ''String Column'' for the remaining columns.
Line 95: Line 100:
 
[[Image:Newcolumnname.jpg|Newcolumnname.jpg]]
 
[[Image:Newcolumnname.jpg|Newcolumnname.jpg]]
  
{{note|Inner Classes|A '''page with table''' is a single Java class. In this example, we're talking about the '''CompanyTablePage'''. The '''table''' itself is an '''inner class''' of the page. The '''columns''' are '''inner classes''' of the table. Take a look at the source to see how that works. The Scout SDK parses the Java code in order to create its model, and the Scout runtime does the same thing. You'll also note that '''annotations''' such as <tt>@Order(30.0)</tt> are used to determine the order of columns in the table.}}
+
{| cellspacing=10 style="border-top: 1px solid black; border-bottom: 1px solid black; margin: 1em; "
 +
!Template
 +
!Name
 +
!TypeName
 +
!Width
 +
!Displayable
 +
|-
 +
|LongColumn
 +
|(none)
 +
|CompanyNrColumn
 +
|(irrelevant)
 +
|no
 +
|-
 +
|StringColumn
 +
|Short Name
 +
|ShortNameColumn
 +
|200
 +
|yes
 +
|-
 +
|StringColumn
 +
|Name
 +
|NameColumn
 +
|200
 +
|yes
 +
|}
 +
 
 +
{{note|Inner Classes|A '''page with table''' is a single Java class. In this example, we're talking about the '''CompanyTablePage'''. The '''table''' itself is an '''inner class''' of the page. The '''columns''' are '''inner classes''' of the table. Take a look at the source files to see how it works. The Scout SDK parses the Java code in order to create its model, and the Scout runtime does the same thing. You'll also note that '''annotations''' such as <tt>@Order(30.0)</tt> are used to determine the order of columns in the table.}}
  
 
== Column Width ==  
 
== Column Width ==  
Line 102: Line 133:
  
 
The '''column width''' could be improved. The table has a property called ''Auto resize columns'' and every column has a property called ''Width''. You can either specify a higher width for all of your columns or you can tell your table to auto resize all columns. When auto resizing, the available width is shared by all columns.
 
The '''column width''' could be improved. The table has a property called ''Auto resize columns'' and every column has a property called ''Width''. You can either specify a higher width for all of your columns or you can tell your table to auto resize all columns. When auto resizing, the available width is shared by all columns.
 +
 +
{{warning|Auto Resizing|Generally speaking you should only use ''auto resize columns'' when '''prototyping'''. In a real application, most '''numbers and dates should be in fixed width columns'''. In addition to that, in some cases you will end up with a lot of columns. Twenty, thirty, and more columns are not unheard of. In this case, fixed columns width and (a lot of) horizontal scrolling is the only solution. Auto resized columns would result in an unreadable mess.}}
 +
 +
If you're not sure, use a width of 200 for text columns.
  
 
{|
 
{|
 
|style="vertical-align:top"|[[Image:Tableprops.jpg]]
 
|style="vertical-align:top"|[[Image:Tableprops.jpg]]
|[[Image:Columnprops.jpg]]
 
 
|}
 
|}
  
{{warning|Auto Resizing|Generally speaking you should only use ''auto resize columns'' when '''prototyping'''. In a real application, most '''numbers and dates should be in fixed width columns'''. In addition to that, in some cases you will end up with a lot of columns. Twenty, thirty, and more columns are not unheard of. In this case, fixed columns width and (a lot of) horizontal scrolling is the only solution. Auto resized columns would result in an unreadable mess.}}
+
{{note|Properties|Setting properties in the Scout SDK needs to leave traces in the Java code because there is no other storage medium. If you look at the property view, you'll note that all the '''bold''' properties have non-default values. The property names act as links. They'll take you to the source code. Setting the width of a column to 200 results in a method being defined for the inner class modeling the column: <tt>protected int getConfiguredWidth() { return 200; }</tt>. This is how Scout properties are mapped: By overriding methods of the abstract classes the framework provides (such as <tt>AbstractStringColumn</tt> etc.).}}
  
 
== Hiding Columns ==
 
== Hiding Columns ==
Line 114: Line 148:
 
In addition to that, users are typically '''not interested in primary keys'''. You should hide ''CompanyNrColumn'' from the user.
 
In addition to that, users are typically '''not interested in primary keys'''. You should hide ''CompanyNrColumn'' from the user.
  
You can do that by unticking the '''Visible''' property on the column. Users can make invisible columns visible, however. If you want to prevent this (and in this case you do), untick the '''Displayable''' property.
+
You can do that by unticking the '''Visible''' property on the column. Users can make invisible columns visible, however. If you want to prevent this (and in this case you do), untick the '''Displayable''' property. To mark the column as a primary key you have to tick the '''Primary Key''' property.
  
 +
Then it will look like this:
 
[[Image:Organize.jpg]]
 
[[Image:Organize.jpg]]
  
{{note|Visible and Displayable Colums|An invisible is only invisible initially. Users can right-click on the column headers of a table and ''organize'' their columns. This is where users can show and hide columns, and this is where they can change their order. '''Invisible columns can be made visible''' using this dialog. If you want to prevent users from making invisible columns visible, you must make them ''not displayable''.}}
+
Note: There are only two columns
  
Sometimes '''invisible but displayable columns''' are used if a certain table is used like a ''report'' for slightly different target users. Some users are interested in a certain subset of columns, other users are interested in a different subset. Instead of preparing a customized table for every target user you can provide one single table for all users with specialized columns being invisible but displayable. Every user then gets to show the particular extra columns they are interested in.
+
{{note|Visible and Displayable Colums|An invisible column is only invisible initially. Users can right-click on the column headers of a table and ''organize'' their columns. This is where users can show and hide columns, and this is where they can change their order. '''Invisible columns can be made visible''' using this dialog. If you want to prevent users from making invisible columns visible, you must make them ''not displayable''.}}
 +
 
 +
Sometimes '''invisible but displayable columns''' are used if a certain table is used like a ''report'' for slightly different target users. Some users are interested in a certain subset of columns, other users are interested in a different subset. Instead of preparing a customized table for every target user, you can provide a single table for all users with specialized columns being invisible but displayable. Every user can then configure the visibility of the particular extra columns they are interested in.
 +
 
 +
== The Flow of Data ==
 +
 
 +
Now that we have our user interface, we need to think about '''flow''': how does the data from the database get into our table?
 +
 
 +
Our table page has a method called '''execLoadTableData'''. We will override its default definition and call our '''outline service''' instead. In order to do this, we'll get a '''proxy''' from the service registry using the <tt>SERVICES</tt> object and the desired interface (''IStandardOutlineService.class'') as the key. We call the '''getCompanyTableData''' method on the proxy, it gets passed to the server, the method is called, the database is queried via the '''SQL''' object, the tabular data is returned to the proxy, it is returned to our function call, finally it will be used to populate the ''CompanyTablePage'' model. This in turn will be used to populate the user interface.
 +
 
 +
[[Image:Scout Table Page Data Flow.png|900px]]
  
 
== Create an Outline Service ==
 
== Create an Outline Service ==
  
In order to fill the table in our ''CompanyTablePage'' we need to have a service available on the server side. This service will contact the database and retrieve the data we need on the client.
+
In order to fill the table in our ''CompanyTablePage'' we need to have a '''service''' available on the server side. This service will contact the database and retrieve the data we need on the client.
  
First, we need to create an ''OutlineService''. Go to the ''server'' node in your Eclipse Scout project, expand it, go to ''Outline Services'', right click and choose ''New Outline Service...''.
+
First, we need to create an ''OutlineService''. Go to the ''server'' node in your Eclipse Scout project, expand it, go to ''Outline Services'', right-click and choose '''New Outline Service...'''.
  
 
[[Image:Newoutlineservice.jpg]]
 
[[Image:Newoutlineservice.jpg]]
  
{{note|Service Types|Services are grouped by ''type'' on the server side. '''Outline''' services are used by the pages "with table" in an outline. '''Process''' services are used by forms (dialogs). '''Lookup''' Services are used by items showing a list of values (smartfields, listboxes).}}
+
{{note|Service Types|Services are grouped by ''type'' on the server side. '''Outline''' services are used by the pages "with table" in an outline. '''Process''' services are used by forms (dialogs). '''Lookup''' services are used by GUI items showing a list of values (smartfields, listboxes).}}
 
+
As name choose ''StandardOutlineService'' since this OutlineService goes together with your ''StandardOutline'' (hence all the TablePages that will in your ''StandardOutline'' in the end will call a service operation in the ''StandardOutlineService'' at the end).
+
  
{{tipp|Organisation Alternatives|There are alternatives to the suggestion above. If you have one big service with a method for every page with table in an outline, you will end up with a big class file. If your outline is big enough such that mutliple developers will be working on it at the same time, this will lead to a lot of merging in your version control system. An alternative is to create ''a separate service per page with table''. This results in a lot more classes and less merge conflicts in a crowded project.}}
+
As name choose ''StandardOutlineService'' since this OutlineService goes together with your ''StandardOutline'' (hence, all the TablePages that belong to your ''StandardOutline'' will call a service operation in the ''StandardOutlineService'').
  
 
[[Image:Standardoutlineservice.jpg]]
 
[[Image:Standardoutlineservice.jpg]]
  
If you click ''next'', you will see that there will be a ''Service Proxy Registration'' in the client plugin of your project. This will support for calling this service's operation from within the client as well.
+
Optional: If you click ''Next'', you will see that the Scout SDK will do a '''Service Proxy Registration''' for you in the client plugin of your project. This allows calling the service operations from within the client as well.
  
 
[[Image:Servicereg.jpg]]
 
[[Image:Servicereg.jpg]]
  
Click on finish in order to create the new service. If you expand now the node ''Outline Services'' you will see a new node ''StandardOutlineService''. Right click on it and choose ''New Service operation''.
+
{{note|Files Affected|If you create the outline service with the default service proxy registration, this will register the service in <tt>eclipse.org.minicrm.client/plugin.xml</tt>. The service ''interface'' is shared between client and server and therefore ends up in <tt>eclipse.org.minicrm.shared.services.outline/IStandardOutlineService.java</tt>. The service implementation itself is in <tt>eclipse.org.minicrm.server.services.outline/StandardOutlineService.java</tt>. The service is also registered in <tt>eclipse.org.minicrm.server/plugin.xml</tt>.}}
 +
 
 +
Click on ''Finish'' in order to create the new service.
 +
 
 +
{{tip|Organisation Alternatives|There are alternatives to the suggestion above. If you have one big service with a method for every page with table in an outline, you will end up with a big class file. If your outline is big enough such that multiple developers will be working on it at the same time, this will lead to a lot of merging in your version control system. An alternative is to create ''a separate service per page with table''. This results in a lot more classes and less merge conflicts in a crowded project.}}
 +
 
 +
Expand the node ''Outline Services'' and you'll see the new ''StandardOutlineService''. Right-click on it and choose '''New Service operation'''.
  
 
[[Image:Newserviceop.jpg]]
 
[[Image:Newserviceop.jpg]]
  
Choose ''getCompanyTableData'' as a name, and as return name enter a double object array ''Object[][]'' and click finish.
+
Choose ''getCompanyTableData'' as the name, and a two-dimensional object array <tt>Object[][]</tt> as the return type and click ''Finish''.
  
 
[[Image:Getcompanytabledata.jpg]]
 
[[Image:Getcompanytabledata.jpg]]
  
It is a good Scout practice to name service operations which collect data to be displayed in a TablePage in a way corresponding to '''''get*TableData'''''.
+
{{note|Object[][]|Why aren't we using typed data to communicate between client and server? On the client side, we have a generic ''load table data'' method that needs to return <tt>Object[][]</tt>. It will call the service we just created. Thus, using <tt>Object[][]</tt> when sending tabular data from the server to the client is nothing but a '''shortcut'''.}}
  
Now open the implementation of ''getCompanyTableData'' either by expanding the node ''StandardOutlineService'' and double clicking on ''getCompanyTableData'' or by opening the class ''StandardOutlineService'' directly (''CTRL-Shift-T'') and scrolling down to ''getCompanyTableData''. This is the place where we have to add an SQL statement which collects the needed data.
+
When naming service operations that provide tabular data for use in table pages, following the pattern '''get'''Something'''TableData''' is a convention and considered good practice.
  
 +
== Load data on the server ==
  
The DB you've downloaded contains the following tables:
+
Open the implementation of ''getCompanyTableData'' either by expanding the node ''StandardOutlineService'' and double-clicking on ''getCompanyTableData'' or by opening the class ''StandardOutlineService'' directly (''Ctrl-Shift-T'') and scrolling down to ''getCompanyTableData''. This is the place where we have to add an SQL statement which retrieves the data from the database.
 +
 
 +
The DB you've downloaded contains the following two tables:
  
 
[[Image:Company.jpg]]
 
[[Image:Company.jpg]]
Line 161: Line 213:
 
[[Image:Person.jpg]]
 
[[Image:Person.jpg]]
  
As described in the [[Scout_Overview|Scout Overview]], Scout provides for a base service ''SQL''. In order to access the DB and select data therefore you need to call ''SQL.select(...)''. When writing your SELECT statement pay attention to specify the db columns in exactly the same order as the order of your table columns. The second parameter, the ''Bind Bases'', are needed to add a constraint to your SELECT statement. For the moment we leave that empty.
+
As described in the [[Scout Overview]], Eclipse Scout provides a base service called <tt>SQL</tt>. In order to access the database and select data, just call <tt>SQL.select(...)</tt>.
 +
 
 +
The first parameter to <tt>SQL.select</tt> is the '''SELECT statement'''.
 +
 
 +
<source lang="java">
 +
public class StandardOutlineService extends AbstractService implements IStandardOutlineService {
 +
 
 +
  public Object[][] getCompanyTableData() throws ProcessingException {
 +
    return SQL.select("" +
 +
        "SELECT COMPANY_NR," +
 +
        "      SHORT_NAME," +
 +
        "      NAME" +
 +
        " FROM  COMPANY");
 +
  }
 +
}
 +
</source>
 +
 
 +
{{warning|Order Considered Relevant|When writing your SELECT statement pay attention to specify the db columns in exactly the same order as the order of your table columns. This is necessarily so because we're just passing an untyped <tt>Object[][]</tt> along. This is an unfortunate consequence of the shortcut we used. As you can see, there are benefits (no packing and unpacking of the tabular data) and drawbacks (the compiler does not check types) to using an untyped <tt>Object[][]</tt>.}}
 +
 
 +
The optional, second parameter to <tt>SQL.select</tt> are the '''Bind Bases'''. They are needed if you need constraints (a WHERE clause with bind variables) in your SELECT statement. We have no need for them right now, since we're going to select ''all'' the companies. Clearly, a typical tutorial example. :)
 +
 
 +
== Display data on the client ==
 +
 
 +
The last thing to do now is to add the call to the ''getCompanyTableData'' service operation, for this we need to overwrite the method ''AbstractPageWithTable.execLoadTableData(SearchFilter)''. Go back to your ''CompanyTablePage'', in the lower part of the properties view click on the ''+'' right to '''Exec Load Table Data''' in order to create this method in your table page.
 +
 
 +
 
 +
[[Image:Execload.jpg|Execload.jpg]]
 +
 
 +
Now you can use the convenience accessor class '''SERVICES''' to find the required service using the ''IStandardOutlineService'' interface class and call ''getCompanyTableData'' to load the data in your TablePage.
 +
 
 +
<source lang="java">
 +
  @Override
 +
  protected Object[][] execLoadTableData(SearchFilter filter) throws ProcessingException {
 +
    return SERVICES.getService(IStandardOutlineService.class).getCompanyTableData();
 +
  }
 +
</source>
  
[[Image:Sql.jpg]]
+
'''Restart your application and enjoy!''' :-)
  
== Load the data for your Page ==
+
[[Image:Simple Scout Application.png]]
The last thing to do is now to add the call to the ''getCompanyTableData'' service operation, for this we need to overwrite the method ''AbstractPageWithTable.execLoadTableData(SearchFilter)''. Go back to your ''CompanyTablePage'', in the lower part of the properties view ''exec'' click on ''Exec Load Table Data'' in order to create this method in your tablepage. When it asks you wether to create the create the method, click on ''Yes''.<br/>[[Image:Execload.jpg|left]]<br clear="all" />Now you can use the convenience accessor class SERVICES to lookup your ''IStandardOutlineService'' class and then call the method ''getCompanyTableData'' to load the data in your TablePage. Now restart your application and enjoy :-)<br/>[[Image:Services.jpg|left]]<br clear="all" />
+

Revision as of 02:39, 3 May 2012

The Scout documentation has been moved to https://eclipsescout.github.io/.

Note.png
Scout Tutorial
This page belongs to the Minicrm Step-by-Step Tutorial. It explains how to create your first page in your project and fill it with data from the database. You need to connect a database to your application in order to continue.


A typical Eclipse Scout application consists of multiple outlines. Think of it as a folder hierarchy. Each "folder" is called a page. These pages come with nodes (a list of child pages) or with a table (a table filled with rows of data from a data source such as a database). The table has named columns. We need to create models for all of these.

If we want to fill the tables with data, we need to create a service on the server side. This service will get data from the database and return tabular data: data arranged in rows and columns which we can use to fill the tables we created on the client side.

Once we have all that we're ready to add a search form to our application.

What are we talking about?

When we talk about outlines and pages, think of a simple application. In this tutorial we're creating a miniature CRM. Here's what it may look like, using the Eclipse Scout terminology:

  1. one outline for companies and persons
    1. the companies page shows a table with rows from the company table on the database
    2. the persons page shows a table with rows from the person table on the database
    3. for every person there is a list of nodes naming all the child pages
  2. there may be other outlines for different tasks or topics, such as marketing campaigns

Scout Pages and Outlines.jpg

If you look at the diagram above, there are some interesting things to note.

  1. the outline itself acts like a page with nodes -- it just shows the titles of the child pages (persons and companies)
  2. there can be only one child page for a page "with table" -- every row in the table has the same child
  3. the title of a child page underneath a table is not shown -- by default the first visible column of the table replaces whatever the name was (in the example above "Catherine" replaces whatever the name of the Person Details Page was)

In this tutorial, our first page will be the company table page. The standard outline is a prerequisite, so we'll start there.

All of these structures are strictly client-side structures. The server couldn't care less about how the various services it provides will get used. The only thing we need on the server side is a service that returns tabular company data.

Add an Outline first

Since a page can only be contained within an Outline, you need to define the Outline first. Open the client node in Eclipse Scout and expand the tree until you reach the Desktop node. Right-click on the node and choose the New Outline... menu.

Newoutline.jpg

Choose Standard as the name and make sure the checkbox Add to Desktop is ticked. Then click Finish.

Newoutlinewizard.jpg

Note.png
Multilingual Texts
If you type Standard into the name field, you'll see all sorts of texts in the language of your locale. If you're not sure whether the string you picked is the right one, you can right-click on it and choose Modify Entry... from the context menu. This will show you the key and all available translations. If you're still not happy, just create a new multilingual text: type Standard into the name field and pick New translated text... from the list.


When you expand the Desktop, you should see the newly created StandardOutline.

Standardoutline.jpg

Note.png
Files Created
If you switch to the Java Perspective, you can have a look at the created files: Package eclipse.org.minicrm.client.ui.desktop.outlines contains the new StandardOutline.java class. If you see the key "SC_Label_UseDefaults" being used in the source code, then you might have picked a multilingual text you did not intend to. Go back to the StandardOutline in the Scout Perspective and modify the entry for the name as discussed above in the note on multilingual texts.


Add a Page to the Outline

Now you can add a new page to your StandardOutline. Right-click on the Child Pages node of your StandardOutline and then choose New Page....

Newpage.jpg

From the dropdown list choose AbstractPageWithTable, then click next.

Newtablepage.jpg

Now enter the name for the new table page: Company.

If there is no appropriate multilingual text, pick New translated text... from the list and provide a key and a default translation.

Newtext.jpg

Companytext.jpg

Note.png
Files Changed
Creating a new translated text will create entries in different property files: Texts.properties for the default language, Texts_de.properties for German, and so on). You can find these property files in the Java Perspective under eclipse.org.minicrm.shared/resources/texts.


Eclipse Scout also comes with an editor to edit all the property files for multilingual texts in one go. If you expand the shared node in your Eclipse Scout project, activate Texts and click on the open nls editor link in the Scout Object properties view. Here you can conveniently manage all your application texts.

Nls.jpg

Back to the CompanyTablePage example: pick Company from the list (create a new translated text if you haven't done so already) and click Finish.

Companytablepage.jpg

When you now expand the Child Pages folder below your StandardOutline, you'll find the new CompanyTablePage. When you expand the node Table, you'll find a folder Menus and Columns. Below Columns we will now add the columns that are needed to display the company data.

Finishedcompanytablepage.jpg

Note.png
Files
Creating the Company Table Page has created the file eclipse.org.minicrm.client.ui.desktop.outlines.pages/CompanyTablePage.java and it has added code to eclipse.org.minicrm.client.ui.desktop.outlines/StandardOutline.java. The newly created method execCreateChildPages in StandardOutline shows how child pages are instantiated and added to the list.


Add colums to the table

The next step is adding columns to the table. Add a column for the primary key (CompanyNrColumn), one for the company's short name (ShortNameColumn) and one for the company's name (NameColumn).

The context menu for creating a new table column is on the Columns node right below the page's table.

Newcolumn.jpg

First you have to choose a template for your column. The template used depends on the data type of your data and the format you want to use when displaying it. Eclipse Scout will attempt to cast your data types appropriately.

Choose Long Column for the first column and String Column for the remaining columns.

Columntemplate.jpg

CompanyNrColumn is going to be an invisible column. Thus, it requires no name. Just provide the Type Name. The remaining columns get multilingual texts for their labels, just like everything else in an Eclipse Scout application.

Newcolumnname.jpg

Template Name TypeName Width Displayable
LongColumn (none) CompanyNrColumn (irrelevant) no
StringColumn Short Name ShortNameColumn 200 yes
StringColumn Name NameColumn 200 yes
Note.png
Inner Classes
A page with table is a single Java class. In this example, we're talking about the CompanyTablePage. The table itself is an inner class of the page. The columns are inner classes of the table. Take a look at the source files to see how it works. The Scout SDK parses the Java code in order to create its model, and the Scout runtime does the same thing. You'll also note that annotations such as @Order(30.0) are used to determine the order of columns in the table.


Column Width

If you restart your client, you will see that the table layout is not optimal.

The column width could be improved. The table has a property called Auto resize columns and every column has a property called Width. You can either specify a higher width for all of your columns or you can tell your table to auto resize all columns. When auto resizing, the available width is shared by all columns.

Warning2.png
Auto Resizing
Generally speaking you should only use auto resize columns when prototyping. In a real application, most numbers and dates should be in fixed width columns. In addition to that, in some cases you will end up with a lot of columns. Twenty, thirty, and more columns are not unheard of. In this case, fixed columns width and (a lot of) horizontal scrolling is the only solution. Auto resized columns would result in an unreadable mess.


If you're not sure, use a width of 200 for text columns.

Tableprops.jpg
Note.png
Properties
Setting properties in the Scout SDK needs to leave traces in the Java code because there is no other storage medium. If you look at the property view, you'll note that all the bold properties have non-default values. The property names act as links. They'll take you to the source code. Setting the width of a column to 200 results in a method being defined for the inner class modeling the column: protected int getConfiguredWidth() { return 200; }. This is how Scout properties are mapped: By overriding methods of the abstract classes the framework provides (such as AbstractStringColumn etc.).


Hiding Columns

In addition to that, users are typically not interested in primary keys. You should hide CompanyNrColumn from the user.

You can do that by unticking the Visible property on the column. Users can make invisible columns visible, however. If you want to prevent this (and in this case you do), untick the Displayable property. To mark the column as a primary key you have to tick the Primary Key property.

Then it will look like this: Organize.jpg

Note: There are only two columns

Note.png
Visible and Displayable Colums
An invisible column is only invisible initially. Users can right-click on the column headers of a table and organize their columns. This is where users can show and hide columns, and this is where they can change their order. Invisible columns can be made visible using this dialog. If you want to prevent users from making invisible columns visible, you must make them not displayable.


Sometimes invisible but displayable columns are used if a certain table is used like a report for slightly different target users. Some users are interested in a certain subset of columns, other users are interested in a different subset. Instead of preparing a customized table for every target user, you can provide a single table for all users with specialized columns being invisible but displayable. Every user can then configure the visibility of the particular extra columns they are interested in.

The Flow of Data

Now that we have our user interface, we need to think about flow: how does the data from the database get into our table?

Our table page has a method called execLoadTableData. We will override its default definition and call our outline service instead. In order to do this, we'll get a proxy from the service registry using the SERVICES object and the desired interface (IStandardOutlineService.class) as the key. We call the getCompanyTableData method on the proxy, it gets passed to the server, the method is called, the database is queried via the SQL object, the tabular data is returned to the proxy, it is returned to our function call, finally it will be used to populate the CompanyTablePage model. This in turn will be used to populate the user interface.

Scout Table Page Data Flow.png

Create an Outline Service

In order to fill the table in our CompanyTablePage we need to have a service available on the server side. This service will contact the database and retrieve the data we need on the client.

First, we need to create an OutlineService. Go to the server node in your Eclipse Scout project, expand it, go to Outline Services, right-click and choose New Outline Service....

Newoutlineservice.jpg

Note.png
Service Types
Services are grouped by type on the server side. Outline services are used by the pages "with table" in an outline. Process services are used by forms (dialogs). Lookup services are used by GUI items showing a list of values (smartfields, listboxes).


As name choose StandardOutlineService since this OutlineService goes together with your StandardOutline (hence, all the TablePages that belong to your StandardOutline will call a service operation in the StandardOutlineService).

Standardoutlineservice.jpg

Optional: If you click Next, you will see that the Scout SDK will do a Service Proxy Registration for you in the client plugin of your project. This allows calling the service operations from within the client as well.

Servicereg.jpg

Note.png
Files Affected
If you create the outline service with the default service proxy registration, this will register the service in eclipse.org.minicrm.client/plugin.xml. The service interface is shared between client and server and therefore ends up in eclipse.org.minicrm.shared.services.outline/IStandardOutlineService.java. The service implementation itself is in eclipse.org.minicrm.server.services.outline/StandardOutlineService.java. The service is also registered in eclipse.org.minicrm.server/plugin.xml.


Click on Finish in order to create the new service.

Idea.png
Organisation Alternatives
There are alternatives to the suggestion above. If you have one big service with a method for every page with table in an outline, you will end up with a big class file. If your outline is big enough such that multiple developers will be working on it at the same time, this will lead to a lot of merging in your version control system. An alternative is to create a separate service per page with table. This results in a lot more classes and less merge conflicts in a crowded project.


Expand the node Outline Services and you'll see the new StandardOutlineService. Right-click on it and choose New Service operation.

Newserviceop.jpg

Choose getCompanyTableData as the name, and a two-dimensional object array Object[][] as the return type and click Finish.

Getcompanytabledata.jpg

Note.png
Object[][]
Why aren't we using typed data to communicate between client and server? On the client side, we have a generic load table data method that needs to return Object[][]. It will call the service we just created. Thus, using Object[][] when sending tabular data from the server to the client is nothing but a shortcut.


When naming service operations that provide tabular data for use in table pages, following the pattern getSomethingTableData is a convention and considered good practice.

Load data on the server

Open the implementation of getCompanyTableData either by expanding the node StandardOutlineService and double-clicking on getCompanyTableData or by opening the class StandardOutlineService directly (Ctrl-Shift-T) and scrolling down to getCompanyTableData. This is the place where we have to add an SQL statement which retrieves the data from the database.

The DB you've downloaded contains the following two tables:

Company.jpg

Person.jpg

As described in the Scout Overview, Eclipse Scout provides a base service called SQL. In order to access the database and select data, just call SQL.select(...).

The first parameter to SQL.select is the SELECT statement.

public class StandardOutlineService extends AbstractService implements IStandardOutlineService {
 
  public Object[][] getCompanyTableData() throws ProcessingException {
    return SQL.select("" +
        "SELECT COMPANY_NR," +
        "       SHORT_NAME," +
        "       NAME" +
        " FROM  COMPANY");
  }
}
Warning2.png
Order Considered Relevant
When writing your SELECT statement pay attention to specify the db columns in exactly the same order as the order of your table columns. This is necessarily so because we're just passing an untyped Object[][] along. This is an unfortunate consequence of the shortcut we used. As you can see, there are benefits (no packing and unpacking of the tabular data) and drawbacks (the compiler does not check types) to using an untyped Object[][].


The optional, second parameter to SQL.select are the Bind Bases. They are needed if you need constraints (a WHERE clause with bind variables) in your SELECT statement. We have no need for them right now, since we're going to select all the companies. Clearly, a typical tutorial example. :)

Display data on the client

The last thing to do now is to add the call to the getCompanyTableData service operation, for this we need to overwrite the method AbstractPageWithTable.execLoadTableData(SearchFilter). Go back to your CompanyTablePage, in the lower part of the properties view click on the + right to Exec Load Table Data in order to create this method in your table page.


Execload.jpg

Now you can use the convenience accessor class SERVICES to find the required service using the IStandardOutlineService interface class and call getCompanyTableData to load the data in your TablePage.

  @Override
  protected Object[][] execLoadTableData(SearchFilter filter) throws ProcessingException {
    return SERVICES.getService(IStandardOutlineService.class).getCompanyTableData();
  }

Restart your application and enjoy! :-)

Simple Scout Application.png

Back to the top