Saturday, December 19, 2009

How Restrictive Should a Structure Be?



[ Team LiB ]





How Restrictive Should a Structure Be?


The large-scale structure patterns discussed in this chapter range from the very loose SYSTEM METAPHOR to the restrictive PLUGGABLE COMPONENT FRAMEWORK. Other structures are possible, of course, and even within a general structural pattern, there is a lot of choice about how restrictive to make the rules.


For example, RESPONSIBILITY LAYERS dictate a kind of factoring of model concepts and their dependencies, but you could add rules that would specify communication patterns between the layers.


Consider a manufacturing plant where software directs each part to a machine where it is processed according to some recipe. The correct process is ordered from a Policy layer and executed in an Operations layer. But inevitably there will be mistakes made on the factory floor. The actual situation will not be consistent with the rules of the software. Now, an Operations layer must reflect the world as it is, which means that when a part is occasionally put in the wrong machine, that information must be accepted unconditionally. Somehow, this exceptional condition needs to be communicated to a higher layer. A decision-making layer can then use other policies to correct the situation, perhaps by rerouting the part to a repair process or by scrapping it. But Operations does not know anything about higher layers. The communication has to be done in a way that doesn't create two-way dependencies from the lower layers to the higher ones.


Typically, this signaling would be done through some kind of event mechanism. The Operations objects would generate events whenever their state changed. Policy layer objects would listen for events of interest from the lower layers. When an event occurred that violated a rule, the rule would execute an action (part of the rule's definition) that makes the appropriate response, or it might generate an event for the benefit of some still higher layer.


In the banking example, the values of assets change (Operations), shifting the values of segments of a portfolio. When these values exceed portfolio allocation limits (Policy), perhaps a trader is alerted, who can buy or sell assets to redress the balance.


We could figure this out on a case-by-case basis, or we could decide on a consistent pattern for everyone to follow in interactions of objects of particular layers. A more restrictive structure increases uniformity, making the design easier to interpret. If the structure fits, the rules are likely to push developers toward good designs. Disparate pieces are likely to fit together better.


On the other hand, the restrictions may take away flexibility that developers need. Very particular communication paths might be impractical to apply across BOUNDED CONTEXTS, especially in different implementation technologies, in a heterogeneous system.


So you have to fight the temptation to build frameworks and regiment the implementation of the large-scale structure. The most important contribution of the large-scale structure is conceptual coherence, and giving insight into the domain. Each structural rule should make development easier.





    [ Team LiB ]



    Text Processing Utilities














    Text Processing Utilities


    Solaris has many user commands available to perform tasks ranging from text processing, to file manipulation, to terminal management. In this section, we will look at some standard UNIX utilities that are the core of using a shell in Solaris. However, readers are urged to obtain an up-to-date list of the utilities supplied with Solaris by typing the command:


    $ man intro

    The cat command displays the contents of a file to standard output, without any kind of pagination or screen control. It is most useful for viewing small files, or for passing the contents of a text file through another filter or utility (for example, the grep command, which searches for strings). To examine the contents of the groups database, for example, we would use this command:


    # cat /etc/group
    root::0:root
    other::1:
    bin::2:root,bin,daemon
    sys::3:root,bin,sys,adm
    adm::4:root,adm,daemon
    uucp::5:root,uucp
    mail::6:root
    tty::7:root,tty,adm
    lp::8:root,lp,adm
    nuucp::9:root,nuucp
    staff::10:
    postgres::100:
    daemon::12:root,daemon
    sysadmin::14:
    nobody::60001:
    noaccess::60002:
    nogroup::65534:

    The cat command is not very useful for examining specific sections of a file. For example, if you need to examine the first few lines of a web server's log files, using cat would display them but they would quickly scroll off the screen out of sight. However, you can use the head command to display only the first few lines of a file. In this example, we extract the lines from the log file of the Inprise application server:



    bart:/usr/local/inprise/ias41/logs/bart/webpageservice > head access_log
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000] "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000] "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000] "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000] "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000] "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000] "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000] "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:53 +1000] "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:53 +1000] "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:53 +1000] "GET /index.jsp HTTP/1.0" 200 24077


    Alternatively, if you just want examine the last few lines of a file, you could use the cat command to display the entire file ending with the last few lines, or you could use the tail command to specifically display these lines. If the file is large (for example, an Inprise application server log file of 2MB), it would be a large waste of system resources to display the whole file using cat, whereas tail is very efficient. Here's an example of using tail to display the last few lines of a file:



    bart:/usr/local/inprise/ias41/logs/bart/webpageservice > tail access_log
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000]
    "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000]
    "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000]
    "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000]
    "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000]
    "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000]
    "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:52 +1000]
    "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:53 +1000]
    "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:53 +1000]
    "GET /index.jsp HTTP/1.0" 200 24077
    203.16.206.43 - - [31/Aug/2000:14:32:53 +1000]
    "GET /index.jsp HTTP/1.0" 200 24077


    Now, imagine that you were searching for a particular string within the access_log file, such as a 404 error code, which indicates that a page has been requested that does not exist. Webmasters regularly check log files for this error code, to create a list of links that need to be checked. To view this list, we can use the grep command to search the file for a specific string (in this case, "404"), and the more command can be use to display the results page by page:



    bart:/usr/local/inprise/ias41/logs/bart/webpageservice > grep 404 access_log | more
    203.16.206.56 - - [31/Aug/2000:15:42:54 +1000] "GET /servlet/LibraryCatalog?command=mainmenu HTTP/1.1" 200 21404
    203.16.206.56 - - [01/Sep/2000:08:32:12 +1000] "GET /servlet/LibraryCatalog?command=searchbyname HTTP/1.1" 200 14041
    203.16.206.237 - - [01/Sep/2000:09:20:35 +1000] "GET /images/L
    INE.gif HTTP/1.1" 404 1204
    203.16.206.236 - - [01/Sep/2000:10:10:35 +1000] "GET /images/L
    INE.gif HTTP/1.1" 404 1204
    203.16.206.236 - - [01/Sep/2000:10:10:40 +1000] "GET /images/L
    INE.gif HTTP/1.1" 404 1204
    203.16.206.236 - - [01/Sep/2000:10:10:47 +1000] "GET /images/L
    INE.gif HTTP/1.1" 404 1204
    203.16.206.236 - - [01/Sep/2000:10:11:09 +1000] "GET /images/L
    INE.gif HTTP/1.1" 404 1204
    203.16.206.236 - - [01/Sep/2000:10:11:40 +1000] "GET /images/L
    INE.gif HTTP/1.1" 404 1204
    203.16.206.236 - - [01/Sep/2000:10:11:44 +1000] "GET /images/L
    INE.gif HTTP/1.1" 404 1204
    203.16.206.236 - - [01/Sep/2000:10:12:03 +1000] "GET /images/L
    INE.gif HTTP/1.1" 404 1204
    203.16.206.41 - - [01/Sep/2000:12:04:22 +1000] "GET /data/books/576586955.pdf H
    TTP/1.0" 404 1204
    --More--


    These log files contain a line for each access to the web server, with entries relating to the source IP address, date and time of access, the HTTP request string sent, the protocol used, and the success/error code. When you see the --More-- prompt, the SPACEBAR can be pressed to advance to the next screen, or the ENTER key can be pressed to advance by a single line in the results. As you have probably guessed, the pipeline operator | was used to pass the results of the grep command through to the more command.


    In addition to the pipeline, there are four other operators that can be used on the command line to direct or append input streams to standard output, or output streams to standard input. Although that sounds convoluted, it can be very useful when working with files to direct the output of a command into a new file (or append it to an existing file). Alternatively, the input to a command can be generated from the output of another command. These operations are performed by the following operators:




    • > Redirect standard output to a file.




    • >> Append standard output to a file.




    • < Redirect file contents to standard input.




    • << Append file contents to standard input.




    Bash also has logical operators, including the 'less than' (lt) operator, which uses the test facility to make numerical comparisons between two operands. Other commonly used operators include




    • a -eq b a equals b.




    • a -ne b a not equal to b.




    • a -gt b a greater than b.




    • a -ge b a greater than or equal to b.




    • a -le b a less than or equal to b.




    Let's look at an example with the cat command, which displays the contents of files, and the echo command, which echoes the contents of a string or an environment variable that has been previously specified. For example, imagine if we wanted to maintain a database of endangered species in a text file called animals.txt. If we wanted to add the first animal "zebra" to an empty file, we could use this command:


    # echo "zebra" > animals.txt

    We could then check the contents of the file animals.txt with the following command:


    # cat animals.txt
    zebra

    Thus, the insertion was successful. Now, imagine that we want to add a second entry (the animal 'emu') to the animals.txt file. We could try using the command


    # echo "emu" > animals.txt

    but the result may not be what we expected:


    # cat animals.txt
    emu

    This is because the > operator always overwrites the contents of an existing file, while the >> operator always appends to the contents of an existing file. Let's run that command again with the correct operators:


    # echo "zebra" > animals.txt
    # echo "emu" > animals.txt

    Luckily, the output is just what we expected:


    # cat animals.txt
    zebra
    emu

    Once we have a file containing a list of all the animals, we would probably want to sort it alphabetically, making searching for specific entries easy. To do this, we can use the sort command:


    # sort animals.txt
    emu
    zebra

    The sorted entries are then displayed on the screen in alphabetical order. It is also possible to redirect the sorted list into another file (called sorted_animals.txt) by using this command:


    # sort animals.txt > animals_sorted.txt

    If you wanted to check that the sorting process actually worked, you could compare the contents of the animals.txt file line by line with the sorted_animals.txt file by using the diff command:


    # diff animals.txt sorted_animals.txt
    1d0
    < zebra
    2a2
    > zebra

    This result indicates that the first and second lines of the animals.txt and sorted_animals.txt files are different, as expected. If the sorting process had failed, the two files would have been identical, and no differences would have been reported by diff.


    A related facility is the basename facility, which is designed to remove file extensions from a filename specified as an argument. This is commonly used to convert files with one extension to another extension. For example, let's imagine that we had a graphic file conversion program that took as its first argument the name of a source JPEG file and took the name of a target bitmap file. Somehow, we'd need to convert a filename of the form filename.jpg to a file of the form filename.bmp. We can do this with the basename command. In order to strip a file extension from an argument, we need to pass the filename and the extension as separate arguments to basename. For example, the command


    # basename maya.gif .gif

    will produce the following output:


    maya

    If we want the .gif extension to be replaced by a .bmp extension, we could use


    # echo `basename maya.gif .gif`.bmp

    which will produce the following output:


    maya.bmp

    Of course, we are not limited to extensions like .gif and .bmp. Also, keep mind that the basename technique is entirely general-and since Solaris does not have mandatory filename extensions, the basename technique can be used for other purposes, such as generating a set of strings based on filenames.











    11.1 Document management and PDM











     < Day Day Up > 











    11.1 Document management and PDM


    Many functions of a DMS are the same, or are very similar to, those of PDM; data storage, CM, and workflow support are parts of both domains. On the other hand, a DMS includes some functions that are only marginally included in PDM or are entirely absent. Document conversion and, in general, different techniques for importing documents of different format or from other media are specific functions of a DMS. Similarly, archiving (long-term storage) of documents is a function characteristic of document management, which is hardly present in PDM. In recent years, we have witnessed that the term document management is often replaced by the term content management. However, these terms are not equivalent. The meaning of document management is slightly different from that of content management. Content management considers in the first place, information (i.e., content itself) and its organization. Many tools include only content management, and many DMSs do not include all of the functionality of content management. However, in general, content management is an integral part of document management. Figure 11.1 shows the overlap of PDM and DMS. There is less overlap between SCM and document management. The document management functions present in both PDM and SCM (e.g., CM and version management) are much more similar to PDM functions than SCM functions. In many PDM tools, document management is its integral part, as described in Section 2.5.2. Several suppliers of PDM have integrated a DMS with their PDM tools. All this makes the boundary between PDM and document management indistinct.






    Figure 11.1: The overlap of DMS and PDM functions.

    Enterprises, the core business of which is information delivery, are by definition in need of a document management tool that keeps effective their internal processes and facilitates the flow of information to customers. If using a DMS, such enterprises have no need for PDM or SCM tools. It may be asked if companies already using a PDM or SCM tool need additional support for document management or if the functions already available are sufficient? The answer to this is that it depends on the intensity of the documentation and information management and the type of documentation handled. A DMS focuses on the life cycle of a document, which is not necessarily the same as a PLC.



















     < Day Day Up > 



    14.3 Testing Decision Structures













    14.3 Testing Decision Structures


    Specifications are often expressed as decision structures, such as sets of conditions on input values and corresponding actions or results. A model of the decision structure can be used to choose test cases that may reveal discrepancies between the decisions actually made in the code and the intended decision structure.


    The example specification of Figure 14.3 describes outputs that depend on type of account (either educational, or business, or individual), amount of current and yearly purchases, and availability of special prices. These can be considered as Boolean conditions, for example, the condition educational account is either true or false (even if the type of account is actually represented in some other manner). Outputs can be described as Boolean expressions over the inputs, for example, the output no discount can be associated with the Boolean expression














    Pricing The pricing function determines the adjusted price of a configuration for a particular customer. The scheduled price of a configuration is the sum of the scheduled price of the model and the scheduled price of each component in the configuration. The adjusted price is either the scheduled price, if no discounts are applicable, or the scheduled price less any applicable discounts.


    There are three price schedules and three corresponding discount schedules, Business, Educational, and Individual. The Business price and discount schedules apply only if the order is to be charged to a business account in good standing. The Educational price and discount schedules apply to educational institutions. The Individual price and discount schedules apply to all other customers. Account classes and rules for establishing business and educational accounts are described further in [].


    A discount schedule includes up to three discount levels, in addition to the possibility of "no discount." Each discount level is characterized by two threshold values, a value for the current purchase (configuration schedule price) and a cumulative value for purchases over the preceding 12 months (sum of adjusted price).



    Educational prices The adjusted price for a purchase charged to an educational account in good standing is the scheduled price from the educational price schedule. No further discounts apply.



    Business account discounts Business discounts depend on the size of the current purchase as well as business in the preceding 12 months. A tier 1 discount is applicable if the scheduled price of the current order exceeds the tier 1 current order threshold, or if total paid invoices to the account over the preceding 12 months exceeds the tier 1 year cumulative value threshold. A tier 2 discount is applicable if the current order exceeds the tier 2 current order threshold, or if total paid invoices to the account over the preceding 12 months exceeds the tier 2 cumulative value threshold. A tier 2 discount is also applicable if both the current order and 12 month cumulative payments exceed the tier 1 thresholds.



    Individual discounts Purchase by individuals and by others without an established account in good standing is based on current value alone (not on cumulative purchases). A tier 1 individual discount is applicable if the scheduled price of the configuration in the current order exceeds the tier 1 current order threshold. A tier 2 individual discount is applicable if the scheduled price of the configuration exceeds the tier 2 current order threshold.



    Special-price nondiscountable offers Sometimes a complete configuration is offered at a special, non-discountable price. When a special, nondiscountable price is available for a configuration, the adjusted price is the nondiscountable price or the regular price after any applicable discounts, whichever is less.










    Figure 14.3: The functional specification of feature Pricing of the Chipmunk Web site.

    When functional specifications can be given as Boolean expressions, we can apply any of the condition testing approaches described in Chapter 12, Section 12.4. A good test suite should at least exercise all elementary conditions occurring in the expression. For simple conditions we might derive test case specifications for all possible combinations of truth values of the elementary conditions. For complex formulas, when testing all 2n combinations of n elementary conditions is apt to be too expensive, the modified decision/condition coverage criterion (page 12.4) derives a small set of test conditions such that each elementary condition independently affects the outcome.


    We can produce different models of the decision structure of a specification depending on the original specification and on the technique we want to use for deriving test cases. If the original specification is expressed informally as in Figure 14.3, we can transform it into either a Boolean expression, a graph, or a tabular model before applying a test case generation technique.


    Techniques for deriving test case specifications from decision structures were originally developed for graph models, and in particular cause-effect graphs, which have been used since the early 1970s. Cause-effect graphs are tedious to derive and do not scale well to complex specifications. Tables, on the other hand, are easy to work with and scale well.


    The rows of a decision table represent basic conditions, and columns represent combinations of basic conditions. The last row of the table indicates the expected outputs for each combination. Cells of the table are labeled either True, False,or don't care (usually written –), to indicate the truth value of the basic condition. Thus, each column is equivalent to a logical expression joining the required values (negated, in the case of False entries) and omitting the basic conditions with don't care values.[2]


    Decision tables can be augmented with a set of constraints that limit the possible combinations of basic conditions. A constraint language can be based on Boolean logic. Often it is useful to add some shorthand notations for common combinations such as at-most-one(C1, , Cn) and exactly-one(C1, , Cn), which are tedious to express with the standard Boolean connectives.



    Figure 14.4 shows the decision table for the functional specification of feature pricing of the Chipmunk Web site presented in Figure 14.3.











    Open table as spreadsheet





































     

    Education



    Individual



    EduAc



    T



    T



    F



    F



    F



    F



    F



    F



    BusAc



    -



    -



    F



    F



    F



    F



    F



    F



    CP > CT1



    -



    -



    F



    F



    T



    T



    -



    -



    YP > YT1



    -



    -



    -



    -



    -



    -



    -



    -



    CP > CT2



    -



    -



    -



    -



    F



    F



    T



    T



    YP > YT2



    -



    -



    -



    -



    -



    -



    -



    -



    SP > Sc



    F



    T



    F



    T



    -



    -



    -



    -



    SP > T1



    -



    -



    -



    -



    F



    T



    -



    -



    SP > T2



    -



    -



    -



    -



    -



    -



    F



    T




    Out



    Edu



    SP



    ND



    SP



    T1



    SP



    T2



    SP






    Open table as spreadsheet





































     

    Business



    EduAc



    -



    -



    -



    -



    -



    -



    -



    -



    -



    -



    -



    -



    BusAc



    T



    T



    T



    T



    T



    T



    T



    T



    T



    T



    T



    T



    CP > CT1



    F



    F



    T



    T



    F



    F



    T



    T



    -



    -



    -



    -



    YP > YT1



    F



    F



    F



    F



    T



    T



    T



    T



    -



    -



    -



    -



    CP > CT2



    -



    -



    F



    F



    -



    -



    -



    -



    T



    T



    -



    -



    YP > YT2



    -



    -



    -



    -



    F



    F



    -



    -



    -



    -



    T



    T



    SP > Sc



    F



    T



    -



    -



    -



    -



    -



    -



    -



    -



    -



    -



    SP > T1



    -



    -



    F



    T



    F



    T



    -



    -



    -



    -



    -



    -



    SP > T2



    -



    -



    -



    -



    -



    -



    F



    T



    F



    T



    F



    T




    Out



    ND



    SP



    T1



    SP



    T1



    SP



    T2



    SP



    T2



    SP



    T2



    SP






    Constraints




















    at-most-one(EduAc, BusAc)



    at-most-one(YP < YT1, YP > YT2)



    YP > YT2 YP > YT1



    at-most-one(CP < CT1, CP > CT2)



    CP > CT2 CP > CT1



    at-most-one(SP < T1, SP > T2)



    SP > T2 SP > T1


     









    Abbreviations



































    EduAc



    Educational account



    Edu



    Educational price



    BusAc



    Business account



    ND



    No discount



    CP > CT1



    Current purchase greater than threshold 1



    T1



    Tier 1



    YP > YT1



    Year cumulative purchase greater than threshold 1



    T2



    Tier 2



    CP > CT2



    Current purchase greater than threshold 2



    SP



    Special Price



    YP > YT2



    Year cumulative purchase greater than threshold 2


      

    SP > Sc



    Special Price better than scheduled price


      

    SP > T1



    Special Price better than tier 1


      

    SP > T2



    Special Price better than tier 2


      

    Open table as spreadsheet








    Figure 14.4: A decision table for the functional specification of feature Pricing of the Chipmunk Web site of Figure 14.3.

    The informal specification of Figure 14.3 identifies three customer profiles: educational, business, and individual. Figure 14.4 has only rows Educational account (EduAc) and Business account (BusAc). The choice individual corresponds to the combination False, False for choices EduAc and BusAc, and is thus redundant. The informal specification of Figure 14.3 indicates different discount policies depending on the relation between the current purchase and two progressive thresholds for the current purchase and the yearly cumulative purchase. These cases correspond to rows 3 through 6 of Figure 14.4. Conditions on thresholds that do not correspond to individual rows in the table can be defined by suitable combinations of values for these rows. Finally, the informal specification of Figure 14.3 distinguishes the cases in which special offer prices do not exceed either the scheduled or the tier 1 or tier 2 prices. Rows 7 through 9 of the table, suitably combined, capture all possible cases of special prices without redundancy.


    Constraints formalize the compatibility relations among different basic conditions listed in the table. For example, a cumulative purchase exceeding threshold tier 2 also exceeds threshold tier 1.


    The basic condition adequacy criterion requires generation of a test case specification for each column in the table. Don't care entries of the table can be filled out arbitrarily, as long as constraints are not violated.


    The compound condition adequacy criterion requires a test case specification for each combination of truth values of basic conditions. The compound condition adequacy criterion generates a number of cases exponential in the number of basic conditions (2n combinations for n conditions) and can thus be applied only to small sets of basic conditions.


    For the modified condition/decision adequacy criterion (MC/DC), each column in the table represents a test case specification. In addition, for each of the original columns, MC/DC generates new columns by modifying each of the cells containing True or False. If modifying a truth value in one column results in a test case specifi modified condition/decision coverage cation consistent with an existing column (agreeing in all places where neither is don't care), the two test cases are represented by one merged column, provided they can be merged without violating constraints.


    The MC/DC criterion formalizes the intuitive idea that a thorough test suite would not only test positive combinations of values - combinations that lead to specified outputs - but also negative combinations of values - combinations that differ from the specified ones - thus, they should produce different outputs, in some cases among the specified ones, in some other cases leading to error conditions.


    Applying MC/DC to column 1 of Figure 14.4 generates two additional columns: one for Educational Account = False and Special Price better than scheduled price = False, and the other for Educational Account = True and Special Price better than scheduled price = True. Both columns are already in the table (columns 3 and 2, respectively) and thus need not be added.


    Similarly, from column 2, we generate two additional columns corresponding to Educational Account = False and Special Price better than scheduled price = True, and Educational Account = True and Special Price better than scheduled price = False, also already in the table.


    Generation of a new column for each possible variation of the Boolean values in the columns, varying exactly one value for each new column, produces 78 new columns, 21 of which can be merged with columns already in the table. Figure 14.5 shows a table obtained by suitably joining the generated columns with the existing ones. Many don't care cells from the original table are assigned either True or False values, to allow merging of different columns or to obey constraints. The few don't-care entries left can be set randomly to obtain a complete test case.







































    EduAc



    T



    T



    F



    F



    F



    F



    F



    F



    F



    F



    F



    F



    F



    F



    F



    BusAc



    F



    F



    F



    F



    F



    F



    F



    F



    T



    T



    T



    T



    T



    T



    T



    CP > CT1



    T



    T



    F



    F



    T



    T



    T



    T



    F



    F



    T



    T



    F



    F



    T



    YP > YT1



    F



    -



    F



    -



    -



    F



    T



    T



    F



    F



    F



    F



    T



    T



    T



    CP > CT2



    F



    F



    F



    F



    F



    F



    T



    T



    F



    F



    F



    F



    F



    F



    F



    YP > YT2



    -



    -



    -



    -



    -



    -



    -



    -



    -



    -



    -



    -



    F



    F



    F



    SP > Sc



    F



    T



    F



    T



    F



    T



    -



    -



    F



    T



    F



    -



    F



    T



    -



    SP > T1



    F



    T



    F



    T



    F



    T



    F



    T



    F



    T



    F



    T



    F



    T



    F



    SP > T2



    F



    -



    F



    -



    F



    -



    F



    T



    F



    -



    F



    -



    F



    -



    F




    Out



    Edu



    SP



    ND



    SP



    T1



    SP



    T2



    SP



    ND



    SP



    T1



    SP



    T1



    SP



    T2



    Open table as spreadsheet




































    EduAc



    F



    F



    F



    F



    F



    T



    T



    T



    T



    F



    -



    BusAc



    T



    T



    T



    T



    T



    F



    F



    F



    F



    F



    F



    CP > CT1



    T



    T



    T



    F



    F



    F



    F



    T



    -



    -



    F



    YP > YT1



    T



    F



    F



    T



    T



    T



    -



    -



    -



    T



    T



    CP > CT2



    F



    T



    T



    F



    F



    F



    F



    T



    T



    F



    F



    YP > YT2



    F



    -



    -



    T



    T



    F



    -



    -



    -



    T



    F



    SP > Sc



    T



    -



    T



    -



    T



    F



    T



    -



    -



    -



    -



    SP > T1



    T



    F



    T



    F



    T



    F



    -



    -



    T



    T



    T



    SP > T2



    T



    F



    T



    F



    T



    F



    F



    F



    T



    T



    -




    Out



    SP



    T2



    SP



    T2



    SP



    Edu



    SP



    Edu



    SP



    SP



    SP



    Open table as spreadsheet



    Abbreviations



































    EduAc



    Educational account



    Edu



    Educational price



    BusAc



    Business account



    ND



    No discount



    CP > CT1



    Current purchase greater than threshold 1



    T1



    Tier 1



    YP > YT1



    Year cumulative purchase greater than threshold 1



    T2



    Tier 2



    CP > CT2



    Current purchase greater than threshold 2



    SP



    Special Price



    YP > YT2



    Year cumulative purchase greater than threshold



    2


     

    SP > Sc



    Special Price better than scheduled price


      

    SP > T1



    Special Price better than tier 1


      

    SP > T2



    Special Price better than tier 2


      

    Open table as spreadsheet



    Figure 14.5: The set of test cases generated for feature Pricing of the Chipmunk Web site applying the modified adequacy criterion.

    There are many ways of merging columns that generate different tables. The table in Figure 14.5 may not be the optimal one - the one with the fewest columns. The objective in test design is not to find an optimal test suite, but rather to produce a cost effective test suite with an acceptable trade-off between the cost of generating and executing test cases and the effectiveness of the tests.


    The table in Figure 14.5 fixes the entries as required by the constraints, while the initial table in Figure 14.4 does not. Keeping constraints separate from the table corresponding to the initial specification increases the number of don't care entries in the original table, which in turn increases the opportunity for merging columns when generating new cases with the MC/DC criterion. For example, if business account (BusAc) = False, the constraint at-most-one(EduAc, BusAc) can be satisfied by assigning either True or False to entry educational account. Fixing either choice prematurely may later make merging with a newly generated column impossible.






    [2]The set of columns sharing a label is therefore equivalent to a logical expression in sum-of-productsform.















    Chapter 2: Resource Acquisition











     < Day Day Up > 












    Chapter 2: Resource Acquisition







    "I find that a great part of the information I have was acquired by looking up something and finding something else on the way."



    Franklin P. Adams









    Overview



    The lifecycle of a resource begins with its acquisition. How and when resources are acquired can play a critical role in the functioning of a software system. By optimizing the time it takes to acquire resources, system performance can be significantly improved.



    Before a resource can be acquired, the most fundamental problem to be solved is how to find a resource. The Lookup (21) pattern addresses this problem and describes how resources can be made available by resource providers, and how these resources can be found by resource users.



    Once a resource has been found, it can be acquired. The timing of resource acquisition is important, and is mainly addressed by Lazy Acquisition (38) and Eager Acquisition (53). While Lazy Acquisition defers acquisition of resources to the latest possible point in time, Eager Acquisition instead strives to acquire resources as early as possible. Both extremes are important and are heavily dependent on the use of the resources.



    If resources that are acquired are not used immediately it can lead to their wastage. Lazy Acquisition addresses this problem and consequently leads to better system scalability. On the other hand, some systems have real-time constraints and stringent requirements for the timing of resource acquisition. Eager Acquisition addresses this problem, and consequently leads to better system performance and predictability.



    A resource of large or unknown size may not be needed completely, and therefore it might be sufficient to acquire only part of the resource. The Partial Acquisition (81) pattern describes how the acquisition of a resource can be partitioned into steps to allow only part of the resource to be acquired. Partial Acquisition can serve as a bridge between Lazy Acquisition and Eager Acquisition. The first step of Partial Acquisition typically acquires part of the resource eagerly, while subsequent steps defer further resource acquisition to a later stage.



    The Lookup pattern can be used with both reusable and non-reusable resources. Furthermore, it can support both concurrently accessible resources and exclusive resources. This is because Lookup only focuses on providing access to resources, and does not deal with how the resources are actually used.



    Lazy Acquisition, Eager Acquisition and Partial Acquisition can also be used with both reusable and non-reusable resources. However, if a reusable resource is concurrently accessible, the three patterns can provide certain optimizations such that the resource is only acquired once and can then be shared by the concurrent users. Such an optimization requires special handling in the case of Partial Acquisition. This is because the amount of a resource that is partially acquired can vary among the concurrent users.


















     < Day Day Up > 



    Summary




    I l@ve RuBoard


    Summary


    In this chapter, we looked at a powerful tool for code reuse: C++ templates. The underlying idea is very simple and attractive: If the algorithms should be the same for different types, you should write it only once and later indicate for what actual type you want this algorithm to be used.



    This is the ideal, but the practical use of this idea faces a number of difficulties. The syntax of C++ templates is complex. The use of specializations complicates matters even more. Sometimes figuring out which specialization will be called in each case becomes a chore. Sometimes, what works on one machine under one compiler will not work on another machine under a different compiler.



    In addition, the use of templates entails space and performance penalty. This is why many C++ programmers try to avoid templates. On the other hand, templates are utilized in the Standard Template Library (STL), and you have to understand the basic principles of using templates to be able to handle the STL library correctly.



    It is a powerful tool. Use it with care.







    I l@ve RuBoard

    How to Use Tables











     < Day Day Up > 





    How to Use Tables



    With the JTable[157] class you can display tables of data, optionally allowing the user to edit the data. JTable doesn't contain or cache data; it's simply a view of your data. (See Figure 69.) The rest of this section tells you how to accomplish some common table-related tasks.

    [157] JTable API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JTable.html.



    Figure 69. A typical table displayed within a scroll pane.




    Creating a Simple Table



    Figure 70 shows a simple table that catalogs personal tidbits about five people.



    Figure 70. The SimpleTableDemo application.




    Try This:















    1. Run SimpleTableDemo using Java Web Start or compile and run the example yourself.[158]

      [158] To run SimpleTableDemo using Java Web Start, click the SimpleTableDemo link on the RunExamples/components.html page on the CD. You can find the source files here: JavaTutorial/uiswing/components/example-1dot4/index.html#SimpleTableDemo.

    2. Click the cell that contains "Snowboarding." The entire first row is selected, indicating that you have selected Mary Campione's data. A special highlight indicates that the "Snowboarding" cell is editable. Generally, you begin editing a text cell by double-clicking it.

    3. Position the cursor over "First Name." Now press the mouse button and drag to the right. As you can see, users can rearrange columns in tables.

    4. Position the cursor just to the right of a column header. Now press the mouse button and drag to the right or left. The column changes size, and the other columns adjust to fill the remaining space.

    5. Resize the window containing the table so that it's bigger than necessary to display the whole table. All the table cells become wider, expanding to fill the extra horizontal space.



    Here's the code that implements the table in SimpleTableDemo:





    String[] columnNames = {"First Name",

    "Last Name",

    "Sport",

    "# of Years",

    "Vegetarian"};



    Object[][] data = {

    {"Mary", "Campione",

    "Snowboarding", new Integer(5), new Boolean(false)},

    {"Alison", "Huml",

    "Rowing", new Integer(3), new Boolean(true)},

    {"Kathy", "Walrath",

    "Knitting", new Integer(2), new Boolean(false)},

    {"Sharon", "Zakhour",

    "Speed reading", new Integer(20), new Boolean(true)},

    {"Philip", "Milne",

    "Pool", new Integer(10), new Boolean(false)}

    };



    JTable table = new JTable(data, columnNames);



    The SimpleTableDemo example uses one of two JTable constructors that directly accept data:



    • JTable(Object[][] rowData, Object[] columnNames)

    • JTable(Vector rowData, Vector columnNames)



    The advantage of these constructors is that they're easy to use. However, these constructors also have disadvantages:



    • They automatically make every cell editable.

    • They treat all data types the same (as strings). For example, if a table column has Boolean data, the table can display the data in a check box. However, if you use one of the two JTable constructors listed previously, your Boolean data will be displayed as a string. You can see this difference in the last column of Figures 69 and 70.

    • They require that you put all of the table's data in an array or vector, which isn't appropriate for some data. For example, if you're instantiating a set of objects from a database, you might want to query the objects directly for their values, rather than copying all their values into an array or vector.



    If you want to get around these restrictions, you need to implement your own table model, as described in Creating a Table Model (page 394).



    Adding a Table to a Container



    It's easy to put a table in a scroll pane. You need just one or two lines of code:





    JScrollPane scrollPane = new JScrollPane(table);

    table.setPreferredScrollableViewportSize(new Dimension(500, 70));



    The scroll pane automatically gets the table's header, which displays the column names, and puts it on top of the table. Even when the user scrolls down, the column names remain visible at the top of the viewing area. The scroll pane also tries to make its viewing area the same as the table's preferred viewing size. The previous code snippet sets the table's preferred viewing size with the setPreferredScrollableViewportSize method.



    If you're using a table without a scroll pane, then you must get the table header component and place it yourself. For example:





    container.setLayout(new BorderLayout());

    container.add(table.getTableHeader(), BorderLayout.PAGE_START);

    container.add(table, BorderLayout.CENTER);



    Setting and Changing Column Widths



    By default, all columns in a table start out with equal width, and the columns automatically fill the entire width of the table. When the table becomes wider or narrower (which might happen when the user resizes the window containing the table), all the column widths change appropriately.



    When the user resizes a column by dragging its right border, then either other columns must change size or the table's size must change. By default, the table's size remains the same, and all columns to the right of the drag point resize to accommodate space added to or removed from the column to the left of the drag point. Figures 71 through 73 illustrate the default resizing behavior.



    Figure 71. Initially, the columns have equal width.




    Figure 73. When the entire table is resized, all the columns are resized.




    Figure 72. When the user resizes a column, some of the other columns must adjust size for the table to stay the same size.




    To customize initial column widths, you can invoke setPreferredWidth on each of your table's columns. This sets both the preferred widths of the columns and their approximate relative widths. For example, adding the following code to SimpleTableDemo makes its third column bigger than the other columns:





    TableColumn column = null;

    for (int i = 0; i < 5; i++) {

    column = table.getColumnModel().getColumn(i);

    if (i == 2) {

    column.setPreferredWidth(100); //sport column is bigger

    } else {

    column.setPreferredWidth(50);

    }

    }



    As the preceding code shows, each column in a table is represented by a TableColumn[159] object. TableColumn supplies getter and setter methods for the minimum, preferred, and maximum widths of a column, as well as a method for getting the current width. For an example of setting cell widths based on the actual amount of space needed to draw the cells' contents, see the initColumnSizes method in TableRenderDemo.java.[160]

    [159] TableColumn API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/table/TableColumn.html.

    [160] You can find TableRenderDemo.java here: JavaTutorial/uiswing/components/example-1dot4/TableRenderDemo.java.



    When the user explicitly resizes columns, the columns' preferred widths are set such that the user-specified sizes become the columns' new current widths. However, when the table itself is resized�typically because the window has resized�the columns' preferred widths do not change. Instead, the existing preferred widths are used to calculate new column widths to fill the available space.



    You can change a table's resize behavior by invoking the setAutoResizeMode method. The method's argument should have one of these values (defined as constants in JTable):



    AUTO_RESIZE_SUBSEQUENT_COLUMNS


    The default. In addition to resizing the column to the left of the drag point, adjusts the sizes of all columns to the right of the drag point.



    AUTO_RESIZE_NEXT_COLUMN


    Adjusts only the columns immediately to the left and right of the drag point.



    AUTO_RESIZE_OFF


    Adjusts the table size instead.



    Detecting User Selections



    The following code snippet shows how to detect when the user selects a table row. By default, a table allows the user to select multiple rows�not columns or individual cells�and the selected rows need not be next to each other. Using the setSelectionMode method, the following code specifies that only one row at a time can be selected.





    table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

    ...

    //Ask to be notified of selection changes.

    ListSelectionModel rowSM = table.getSelectionModel();

    rowSM.addListSelectionListener(new ListSelectionListener() {

    public void valueChanged(ListSelectionEvent e) {

    //Ignore extra messages.

    if (e.getValueIsAdjusting()) return;



    ListSelectionModel lsm =

    (ListSelectionModel)e.getSource();

    if (lsm.isSelectionEmpty()) {

    ...//no rows are selected

    } else {

    int selectedRow = lsm.getMinSelectionIndex();

    ...//selectedRow is selected

    }

    }

    });



    The code is from SimpleTableSelectionDemo.java.[161] SimpleTableSelectionDemo also has code (not included in the preceding snippet) that changes the table's selection orientation. By changing a couple of boolean values, you can make the table allow either column selections or individual cell selections, instead of row selections.

    [161] You can find SimpleTableSelectionDemo.java here: JavaTutorial/uiswing/components/example-1dot4/SimpleTableSelectionDemo.java.



    For more information and examples of implementing selection, see How to Write a List Selection Listener (page 685) in Chapter 10.



    Creating a Table Model



    As Figure 74 shows, every table gets its data from an object that implements the Table-Model[162] interface.

    [162] TableModel API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/table/TableModel.html.



    Figure 74. Every table gets its data from TableModel.




    The JTable constructor used by SimpleTableDemo creates its table model with code like this:





    new AbstractTableModel() {

    public String getColumnName(int col) {

    return columnNames[col].toString();

    }

    public int getRowCount() { return rowData.length; }

    public int getColumnCount() { return columnNames.length; }

    public Object getValueAt(int row, int col) {

    return rowData[row][col];

    }

    public boolean isCellEditable(int row, int col)

    { return true; }

    public void setValueAt(Object value, int row, int col) {

    rowData[row][col] = value;

    fireTableCellUpdated(row, col);

    }

    }



    As the preceding code shows, implementing a table model can be simple. Generally, you implement your table model in a subclass of the AbstractTableModel[163] class.

    [163] AbstractTableModel API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/table/AbstractTableModel.html.



    Your model might hold its data in an array, vector, or hash map, or it might get the data from an outside source such as a database. It might even generate the data at execution time.



    Figure 75 is a picture of a table implemented by TableDemo (which you can run using Java Web Start[164] ) that has a custom table model.

    [164] To run TableDemo using Java Web Start, click the TableDemo link on the RunExamples/components.html page on the CD. You can find the source files here: JavaTutorial/uiswing/components/example-1dot4/index.html#TableDemo.



    Figure 75. The table implemented by the TableDemo application.




    This table is different from the SimpleTableDemo table in the following ways:



    • TableDemo's custom table model, even though it's simple, can easily determine the data's type, helping the JTable display the data in the best format. SimpleTableDemo's automatically created table model, on the other hand, isn't smart enough to know that the # of Years column contains numbers (which should generally be right aligned and have a particular format). It also doesn't know that the Vegetarian column contains boolean values, which can be represented by check boxes.

    • In TableDemo, we implemented the custom table model so that it doesn't let you edit the name columns; it does, however, let you edit the other columns. In SimpleTableDemo, all cells are editable.



    Below is the code from TableDemo.java that is different from the code in SimpleTableDemo.java. Bold font indicates the code that makes this table's model different from the table model defined automatically for SimpleTableDemo.





    public TableDemo() {

    ...

    JTable table = new JTable(new MyTableModel());

    ...

    }

    class MyTableModel extends AbstractTableModel {

    private String[] columnNames = ...//same as before...

    private Object[][] data = ...//same as before...



    public int getColumnCount() {

    return columnNames.length;

    }



    public int getRowCount() {

    return data.length;

    }



    public String getColumnName(int col) {

    return columnNames[col];

    }



    public Object getValueAt(int row, int col) {

    return data[row][col];

    }



    public Class getColumnClass(int c) {

    return getValueAt(0, c).getClass();

    }



    /*

    * Don't need to implement this method unless your table's

    * editable.

    */

    public boolean isCellEditable(int row, int col) {

    //Note that the data/cell address is constant,

    //no matter where the cell appears onscreen.

    if (col < 2) {

    return false;

    } else {

    return true;

    }

    }



    /*

    * Don't need to implement this method unless your table's

    * data can change.

    */

    public void setValueAt(Object value, int row, int col) {

    data[row][col] = value;

    fireTableCellUpdated(row, col);

    }

    ...

    }



    Detecting Data Changes



    A table and its model automatically detect whenever the user edits the table's data. However, if the data changes for another reason, you must take special steps to notify the table and its model of the data change. Also, if you don't implement a table model, as in SimpleTableDemo, then you must take special steps to find out when the user edits the table's data.



    An example of updating a table's data without directly editing it is in the BINGO application. The BINGO application, presented in "Putting It All Together,"[165] has a table that displays some information about each user who is signed up to play the game. When a new user signs up to play BINGO, the table needs to add a new row for that user. More precisely, the table model needs to get the data for the new user, and then the table model needs to tell the table to display the new data.

    [165] The BINGO! game is featured in The Java Tutorial trail "Putting It All Together," available online and on the CD at: JavaTutorial/together/bingo/index.html.



    To notify the table model about a new user, the BINGO application invokes the table model's updatePlayer method. You can see the code for that method in PlayerInfoModel,[166] which contains the implementation of the table model. The updatePlayer method records the new user's data and fires a table-model event. Because every table listens for table-model events from its model, the user-information table automatically detects the change and displays the new data.

    [166] You can find all the code needed to play BINGO! online and on the CD at: JavaTutorial/together/bingo/letsplay.html#download.



    To fire the table-model event, the model invokes the fireTableRowsInserted method, which is defined by the AbstractTableModel class. Other fireXxxx methods that AbstractTableModel defines are fireTableCellUpdated, fireTableChanged, fire-TableDataChanged, fireTableRowsDeleted, fireTableRowsInserted, fireTableRows-Updated, and fireTableStructureChanged.



    If you have a class such as SimpleTableDemo that isn't a table or table model, but needs to react to changes in a table model, then you need to do something special to find out when the user edits the table's data. Specifically, you need to register a TableModelListener[167] on the table model. Adding the bold code in the following snippet makes SimpleTableDemo react to table data changes.

    [167] TableModelListener API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/event/TableModelListener.html.





    import javax.swing.event.*;

    import javax.swing.table.TableModel;



    public class SimpleTableDemo ... implements TableModelListener {

    ...

    public SimpleTableDemo() {

    ...

    table.getModel().addTableModelListener(this);

    ...

    }



    public void tableChanged(TableModelEvent e) {

    int row = e.getFirstRow();

    int column = e.getColumn();

    TableModel model = (TableModel)e.getSource();

    String columnName = model.getColumnName(column);

    Object data = model.getValueAt(row, column);



    ...// Do something with the data...

    }

    ...

    }



    Concepts: Editors and Renderers



    Before you go on to the next few tasks, you need to understand how tables draw their cells. You might expect each cell in a table to be a component. However, for performance reasons, Swing tables aren't implemented that way.



    Instead, a single cell renderer is generally used to draw all of the cells that contain the same type of data. You can think of the renderer as a configurable ink stamp that the table uses to stamp appropriately formatted data onto each cell. When the user starts to edit a cell's data, a cell editor takes over the cell, controlling the cell's editing behavior.



    For example, each cell in the # of Years column in TableDemo contains Number data�specifically, an Integer object. By default, the cell renderer for a Number-containing column uses a single JLabel instance to draw the appropriate numbers, right-aligned, on the column's cells. If the user begins editing one of the cells, the default cell editor uses a right-aligned JTextField to control the cell editing.



    To choose the renderer that displays the cells in a column, a table first determines whether you specified a renderer for that particular column. (We'll tell you how to specify renderers a bit later.) If you didn't, then the table invokes the table model's getColumnClass method, which gets the data type of the column's cells. Next, the table compares the column's data type with a list of data types for which cell renderers are registered. This list is initialized by the table, but you can add to it or change it. Currently, tables put the following types of data in the list:





    • Boolean

      rendered with a check box.



    • Number

      rendered by a right-aligned label.



    • Double, Float

      same as Number, but the object-to-text translation is performed by a NumberFormat[168] instance (using the default number format for the current locale).

      [168] NumberFormat API documentation: http://java.sun.com/j2se/1.4.2/docs/api/java/text/NumberFormat.html.



    • Date[169]

      rendered by a label, with the object-to-text translation performed by a DateFormat instance (using a short style for the date and time).

      [169] DateFormat API documentation: http://java.sun.com/j2se/1.4.2/docs/api/java/text/DateFormat.html.



    • ImageIcon, Icon

      rendered by a centered label.



    • Object

      rendered by a label that displays the object's string value.





    Version Note:

    The default renderer associations for Double, Float, and Icon were added in release 1.3.




    Cell editors are chosen using a similar algorithm.



    Remember that if you let a table create its own model, it uses Object as the type of every column. To specify more precise column types, the table model must define the getColumnClass method appropriately, as demonstrated by TableDemo.java.



    Keep in mind that although renderers determine how each cell or column header looks and can specify its tool tip text, renderers don't handle events. If you need to pick up the events that take place inside a table, the technique you use varies by the sort of event you're interested in.



    Situation

    How to Get Events

    To detect events from a cell that's being edited

    Use the cell editor (or register a listener on the cell editor).

    To detect row/column/cell selections and deselections

    Use a selection listener as described in Detecting User Selections (page 393).

    To detect mouse events on a column header

    Register the appropriate type of mouse listener on the table's JTableHeader object. (See TableSorter.java for an example.[a])

    To detect other events

    Register the appropriate listener on the JTable object.

    [a] You can find TableSorter.java here: JavaTutorial/uiswing/components/example-1dot4/TableSorter.java.



    The next few sections tell you how to customize display and editing by specifying renderers and editors. You can specify cell renderers and editors either by column or by data type.



    Using a Combo Box as an Editor



    Setting up a combo box as an editor is simple, as the following example shows. The bold line of code sets up the combo box as the editor for a specific column.





    TableColumn sportColumn = table.getColumnModel().getColumn(2);

    ...

    JComboBox comboBox = new JComboBox();

    comboBox.addItem("Snowboarding");

    comboBox.addItem("Rowing");

    comboBox.addItem("Chasing toddlers");

    comboBox.addItem("Speed reading");

    comboBox.addItem("Teaching high school");

    comboBox.addItem("None");

    sportColumn.setCellEditor(new DefaultCellEditor(comboBox));



    Figure 76 is a picture of the combo box editor in use.



    Figure 76. The TableRenderDemo application.




    You can run this example, TableRenderDemo, using Java Web Start.[170]

    [170] To run TableRenderDemo using Java Web Start, click the TableRenderDemo link on the RunExamples/components.html page on the CD. You can find the source files here: JavaTutorial/uiswing/components/example-1dot4/index.html#TableRenderDemo.



    Using an Editor to Validate User-Entered Text



    If a cell's default editor allows text entry, you get some error checking for free if the cell's type is specified as something other than String or Object. The error checking is a side effect of converting the entered text into an object of the proper type.





    Version Note:

    Before 1.3, the default implementation did not in any way restrict the string that could be entered and didn't convert it from a String. You needed to put some ugly code in the model's setValueAt method to parse the entered string and prevent the cell's value from becoming a String.




    The automatic checking of user-entered strings occurs when the default editor attempts to create a new instance of the class associated with the cell's column. The default editor creates this instance using a constructor that takes a String as an argument. For example, in a column whose cells have type Integer, when the user types in "123" the default editor creates the corresponding Integer using code equivalent to new Integer("123"). If the constructor throws an exception, the cell's outline turns red and refuses to let the focus move out of the cell. If you implement a class used as a column data type, you can use the default editor if your class supplies a constructor that takes a single argument of type String.



    If you like having a text field as the editor for a cell, but want to customize it�perhaps to check user-entered text more strictly or to react differently when the text is invalid�you can change the cell editor to use a formatted text field. The formatted text field can check the value either continuously while the user is typing or after the user has indicated the end of typing (such as by pressing Enter).



    You can run TableFTFEditDemo using Java Web Start.[171] The following code, taken from a demo named TableFTFEditDemo, sets up a formatted text field as an editor that limits all integer values to be between 0 and 100. It also makes the formatted text field the editor for all columns that contain data of type Integer:

    [171] To run TableFTFEditDemo using Java Web Start, click the TableFTFEditDemo link on the RunExamples/components.html page on the CD. You can find the source files here: JavaTutorial/uiswing/components/example-1dot4/index.html#TableFTFEditDemo.





    table.setDefaultEditor(Integer.class, new IntegerEditor(0, 100));



    The IntegerEditor class is implemented as a subclass of DefaultCellEditor[172] that uses a JFormattedTextField instead of the JTextField that DefaultCellEditor supports. It accomplishes this by first setting up a formatted text field to use an integer format and have the specified minimum and maximum values, using the API described in How to Use Formatted Text Fields (page 221). It then overrides the DefaultCellEditor implementation of the getTableCellEditorComponent, getCellEditorValue, and stopCellEditing methods, adding the operations that are necessary for formatted text fields.

    [172] DefaultCellEditor API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/DefaultCellEditor.html.



    The override of getTableCellEditorComponent sets the formatted text field's value property (and not just the text property it inherits from JTextField) before the editor is shown. The override of getCellEditorValue keeps the cell value as an Integer, rather than, say, the Long value that the formatted text field's parser tends to return. Finally, overriding stopCellEditing lets us check whether the text is valid, possibly stopping the editor from being dismissed. If the text isn't valid, our implementation of stopCellEditing puts up a dialog that gives the user the option of continuing to edit or reverting to the last good value. The source code is a bit too long to include here, but you can find it in IntegerEditor.java.[173]

    [173] IntegerEditor.java is on the CD at: JavaTutorial/uiswing/components/example-1dot4/IntegerEditor.java.



    Using Other Editors



    Whether you're setting the editor for a single column of cells (using the TableColumn setCellEditor method) or for a specific type of data (using the JTable setDefaultEditor method), you specify the editor using an argument that adheres to the TableCellEditor interface. Fortunately, the DefaultCellEditor class implements this interface and provides constructors to let you specify an editing component that's a JTextField, JCheckBox, or JComboBox. You usually don't have to explicitly specify a check box as an editor, since columns with Boolean data automatically use a check box renderer and editor.



    What if you want to specify an editor that isn't a text field, check box, or combo box? Well, because DefaultCellEditor doesn't support other types of components, you must do a little more work. You need to create a class that implements the TableCellEditor[174] interface. The AbstractCellEditor[175] class is a good superclass to use. It implements TableCell-Editor's superinterface, CellEditor,[176] saving you the trouble of implementing the event firing code necessary for cell editors.

    [174] TableCellEditor API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/table/TableCellEditor.html.

    [175] AbstractCellEditor API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/AbstractCellEditor.html.

    [176] CellEditor API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/CellEditor.html.



    Your cell editor class needs to define at least two methods�getCellEditorValue and getTableCellEditorComponent. The getCellEditorValue method, required by CellEditor, returns the cell's current value. The getTableCellEditorComponent method, required by TableCellEditor, should configure and return the component that you want to use as the editor.





    Version Note:

    The AbstractCellEditor class was added in v1.3. Before then, implementing a cell editor for a new component type was much more difficult, since you had to implement all the CellEditor methods yourself.




    Figure 77 is a picture of a table with a dialog that serves, indirectly, as a cell editor. When the user begins editing a cell in the Favorite Color column, a button (the true cell editor) appears and brings up the dialog, with which the user can choose a different color.



    Figure 77. The TableDialogEditDemo application with the "Pick a Color" dialog.




    You can run TableDialogEditDemo using Java Web Start or compile and run it yourself.[177] Here's the code, taken from ColorEditor.java, that implements the cell editor:

    [177] To run TableDialogEditDemo using Java Web Start, click the TableDialogEditDemo link on the RunExamples/components.html page on the CD. You can find the source files here: JavaTutorial/uiswing/components/example-1dot4/index.html#TableDialogEditDemo.





    public class ColorEditor extends AbstractCellEditor

    implements TableCellEditor,

    ActionListener {

    Color currentColor;

    JButton button;

    JColorChooser colorChooser;

    JDialog dialog;

    protected static final String EDIT = "edit";



    public ColorEditor() {

    button = new JButton();

    button.setActionCommand(EDIT);

    button.addActionListener(this);

    button.setBorderPainted(false);



    //Set up the dialog that the button brings up.

    colorChooser = new JColorChooser();

    dialog = JColorChooser.createDialog(

    button,

    "Pick a Color",

    true, //modal

    colorChooser,

    this, //OK button handler

    null); //no CANCEL button handler

    }



    public void actionPerformed(ActionEvent e) {

    if (EDIT.equals(e.getActionCommand())) {

    //The user has clicked the cell, so

    //bring up the dialog.

    button.setBackground(currentColor);

    colorChooser.setColor(currentColor);

    dialog.setVisible(true);



    fireEditingStopped(); //Make the renderer reappear.



    } else { //User pressed dialog's "OK" button.

    currentColor = colorChooser.getColor();

    }

    }



    //Implement the one CellEditor method that AbstractCellEditor doesn't.

    public Object getCellEditorValue() {

    return currentColor;

    }

    //Implement the one method defined by TableCellEditor.

    public Component getTableCellEditorComponent(JTable table,

    Object value,

    boolean isSelected,

    int row,

    int column) {

    currentColor = (Color)value;

    return button;

    }

    }



    As you can see, the code is pretty simple. The only part that's a bit tricky is the call to fireEditingStopped at the end of the editor button's action handler. Without this call, the editor would remain active, even though the modal dialog is no longer visible. The call to fireEditingStopped lets the table know that it can deactivate the editor, letting the cell be handled by the renderer again.



    Using Custom Renderers



    This section tells you how to create and specify a cell renderer. You can set a type-specific cell renderer using the JTable method setDefaultRenderer. To specify that cells in a particular column should use a renderer, use the TableColumn method setCellRenderer. You can even specify a cell-specific renderer by creating a JTable subclass, as we'll show later.



    It's easy to customize the text or image rendered by the default renderer, DefaultTableCellRenderer. You just create a subclass and implement the setValue method so that it invokes setText or setIcon with the appropriate string or image. For example, here is how the default date renderer is implemented:





    static class DateRenderer extends DefaultTableCellRenderer {

    DateFormat formatter;

    public DateRenderer() { super(); }



    public void setValue(Object value) {

    if (formatter==null) {

    formatter = DateFormat.getDateInstance();

    }

    setText((value == null) ? "" : formatter.format(value));

    }

    }



    If extending DefaultTableCellRenderer doesn't do the trick, you can build a renderer using another superclass. The easiest way is to create a subclass of an existing component, making your subclass implement the TableCellRenderer[178] interface. TableCellRenderer requires just one method: getTableCellRendererComponent. Your implementation of this method should set up the rendering component to reflect the passed-in state, and then return the component.

    [178] TableCellRenderer API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/table/TableCellRenderer.html.



    In Figure 77 (page 403), TableDialogEditDemo's renderer used for Favorite Color cells is a subclass of JLabel called ColorRenderer. Here are excerpts from ColorRenderer.java that show how it's implemented:[179]

    [179] ColorRenderer.java is on the CD at: JavaTutorial/uiswing/components/example-1dot4/ColorRenderer.java.





    public class ColorRenderer extends JLabel

    implements TableCellRenderer {

    ...

    public ColorRenderer(boolean isBordered) {

    this.isBordered = isBordered;

    setOpaque(true); //MUST do this for background to show up.

    }



    public Component getTableCellRendererComponent(

    JTable table, Object color,

    boolean isSelected, boolean hasFocus,

    int row, int column) {

    Color newColor = (Color)color;

    setBackground(newColor);

    if (isBordered) {

    if (isSelected) {

    ...

    //selectedBorder is a solid border in the color

    //table.getSelectionBackground().

    setBorder(selectedBorder);

    } else {

    ...

    //unselectedBorder is a solid border in the color

    //table.getBackground().

    setBorder(unselectedBorder);

    }

    }



    setToolTipText(...); //Discussed in the following section

    return this;

    }

    }



    Here's the code from TableDialogEditDemo.java[180] that registers a ColorRenderer instance as the default renderer for all Color data:

    [180] TableDialogEditDemo.java on the CD at: JavaTutorial/uiswing/components/example-1dot4/TableDialogEditDemo.java.





    table.setDefaultRenderer(Color.class, new ColorRenderer(true));



    The next section shows a couple of examples of using TableColumn's setCellRenderer method, so we'll skip that for now and show you how to specify a renderer for a particular cell. To specify a cell-specific renderer, you need to define a JTable subclass that overrides the getCellRenderer method. For example, the following code makes the first cell in the first column of the table use a custom renderer:





    TableCellRenderer weirdRenderer = new WeirdRenderer();

    table = new JTable(...) {

    public TableCellRenderer getCellRenderer(int row, int column) {

    if ((row == 0) && (column == 0)) {

    return weirdRenderer;

    }

    // else...

    return super.getCellRenderer(row, column);

    }

    };



    Specifying Tool Tips for Cells



    By default, the tool tip text displayed for a table cell is determined by the cell's renderer. However, sometimes it can be simpler to specify tool tip text by overriding JTable's implementation of the getToolTipText(MouseEvent) method. This section tells you how to use both techniques.



    To add a tool tip to a cell using its renderer, you first need to get or create the cell renderer. Then, after making sure the rendering component is a JComponent, invoke the setToolTipText method on it.



    An example of setting tool tips for cells is in TableRenderDemo, which you can run using Java Web Start or compile and run yourself.[181] It adds tool tips to the cells of the Sport column with the following code:

    [181] To run TableRenderDemo using Java Web Start, click the TableRenderDemo link on the RunExamples/components.html page on the CD. You can find the source files here: JavaTutorial/uiswing/components/example-1dot4/index.html#TableRenderDemo.





    //Set up tool tips for the sport cells.

    DefaultTableCellRenderer renderer =

    new DefaultTableCellRenderer();

    renderer.setToolTipText("Click for combo box");

    sportColumn.setCellRenderer(renderer);



    Figure 78 is a picture of the resulting tool tip:



    Figure 78. A tool tip for cells in the Sport column.




    Although the tool tip text in the previous example is static, you can also implement tool tips whose text changes depending on the state of the cell or program. Here are a couple ways to do so:



    • Add a bit of code to the renderer's implementation of the getTableCellRenderer-Component method.

    • Override the JTable method getToolTipText(MouseEvent).



    An example of adding code to a cell renderer is in TableDialogEditDemo, which you can run using Java Web Start or compile and run yourself.[182] TableDialogEditDemo uses a renderer for colors, implemented in ColorRenderer.java, that sets the tool tip text using the boldface code in the following snippet:

    [182] To run TableDialogEditDemo using Java Web Start, click the TableDialogEditDemo link on the RunExamples/components.html page on the CD. You can find the source files here: JavaTutorial/uiswing/components/example-1dot4/index.html#TableDialogEditDemo.





    public class ColorRenderer extends JLabel

    implements TableCellRenderer {

    ...

    public Component getTableCellRendererComponent(

    JTable table, Object color,

    boolean isSelected, boolean hasFocus,

    int row, int column) {

    Color newColor = (Color)color;

    ...

    setToolTipText("RGB value: " + newColor.getRed() + ", "

    + newColor.getGreen() + ", "

    + newColor.getBlue());

    return this;

    }

    }



    Figure 79 is an example of what the tool tip looks like.



    Figure 79. A tool tip showing the RGB value of the selected color.




    As we mentioned before, you can specify tool tip text by overriding JTable's getToolTipText(MouseEvent) method. The program TableToolTipsDemo[183] shows how. The cells with tool tips are in the Sport and Vegetarian columns. (See Figure 80.)

    [183] To run TableToolTipsDemo using Java Web Start, click the TableToolTipsDemo link on the RunExamples/components.html page on the CD. You can find the source files here: JavaTutorial/uiswing/components/example-1dot4/index.html#TableToolTipsDemo.



    Figure 80. An example of a customized tool tip for the Vegetarian column.




    Here's the code from TableToolTipsDemo.java that implements tool tips for cells in the Sport and Vegetarian columns:





    JTable table = new JTable(new MyTableModel()) {

    //Implement table cell tool tips.

    public String getToolTipText(MouseEvent e) {

    String tip = null;

    java.awt.Point p = e.getPoint();

    int rowIndex = rowAtPoint(p);

    int colIndex = columnAtPoint(p);

    int realColumnIndex = convertColumnIndexToModel(colIndex);



    if (realColumnIndex == 2) { //Sport column

    tip = "This person's favorite sport to "

    + "participate in is: "

    + getValueAt(rowIndex, colIndex);

    } else if (realColumnIndex == 4) { //Veggie column

    TableModel model = getModel();

    String firstName = (String)model.getValueAt(rowIndex,0);

    String lastName = (String)model.getValueAt(rowIndex,1);

    Boolean veggie = (Boolean)model.getValueAt(rowIndex,4);

    if (Boolean.TRUE.equals(veggie)) {

    tip = firstName + " " + lastName

    + " is a vegetarian";

    } else {

    tip = firstName + " " + lastName

    + " is not a vegetarian";

    }



    } else { //another column

    //You can omit this part if you know you don't

    //have any renderers that supply their own tool

    //tips.

    tip = super.getToolTipText(e);

    }

    return tip;

    }

    ...

    }



    The code is fairly straightforward, except perhaps for the call to convertColumnIndexToModel, which is necessary because if the user moves the columns around, the view's index for the column doesn't match the model's index for it. For example, the user might drag the Vegetarian column (which the model considers to be at index 4) so that it's displayed as the first column�at view index 0. Since prepareRenderer gives us the view index, we need to translate the view index to a model index to be sure that we're dealing with the intended column.



    Specifying Tool Tips for Column Headers



    You can add a tool tip to a column header by setting the tool tip text for the table's JTableHeader. Often, different column headers require different tool tip text. You can change the text by overriding the table header's getToolTipText(MouseEvent) method.



    An example of using the same tool tip text for all column headers is in TableSorterDemo.[184] Here's how it sets the tool tip text:

    [184] To run TableSorterDemo using Java Web Start, click the TableSorterDemo link on the RunExamples/components.html page on the CD. You can find the source files here: JavaTutorial/uiswing/components/example-1dot4/index.html#TableSorterDemo.





    table.getTableHeader().setToolTipText(

    "Click to sort; Shift-Click to sort in reverse order");



    TableToolTipsDemo has an example of implementing column header tool tips that vary by column. If you run TableToolTipsDemo,[185] you'll see the tool tips when you mouse over any column header except for the first two (see Figure 81). We elected not to supply tool tips for the name columns since they seemed self-explanatory. (Actually, we just wanted to show you that it could be done.)

    [185] To run TableToolTipsDemo using Java Web Start, click the TableToolTipsDemo link on the RunExamples/components.html page on the CD. You can find the source files here: JavaTutorial/uiswing/components/example-1dot4/index.html#TableToolTipsDemo.



    Figure 81. The column header tool tip for the # of Years column.




    The following code implements the tool tips. Basically, it creates a subclass of JTableHeader that overrides the getToolTipText(MouseEvent) method so that it returns the text for the current column. To associate the revised table header with the table, the JTable method createDefaultTableHeader is overridden so that it returns an instance of the JTableHeader subclass.





    protected String[] columnToolTips = {

    null,

    null,

    "The person's favorite sport to participate in",

    "The number of years the person has played the sport",

    "If checked, the person eats no meat"};

    ...



    JTable table = new JTable(new MyTableModel()) {

    ...



    //Implement table header tool tips.

    protected JTableHeader createDefaultTableHeader() {

    return new JTableHeader(columnModel) {

    public String getToolTipText(MouseEvent e) {

    String tip = null;

    java.awt.Point p = e.getPoint();

    int index = columnModel.getColumnIndexAtX(p.x);

    int realIndex =

    columnModel.getColumn(index).getModelIndex();

    return columnToolTips[realIndex];

    }

    };

    }

    };





    Version Note:



    Before 1.3, each column had its own header renderer, and you could use the value returned by the TableColumn method getHeaderRenderer to set a tool tip for a specific column header. For performance reasons, the default behavior is now to use a single renderer for all column headers, and getHeaderRenderer returns null. The default header renderer used for all columns is returned by the TableHeader method getDefaultRenderer, which was added in 1.3.




    Sorting and Otherwise Manipulating Data



    One way to perform data manipulation such as sorting is to use one or more specialized table models (data manipulators), in addition to the table model that provides the data (the data model). The data manipulators should sit between the table and the data model, as Figure 82 shows.



    Figure 82. Data manipulators sit between the table and the data model.




    If you decide to implement a data manipulator, take a look at TableMap.java and TableSorter.java.[186] The TableMap class implements TableModel and serves as a superclass for data manipulators. TableSorter is a TableMap subclass that sorts the data provided by another table model. You can either change these classes, using them as a basis for writing your own data manipulator, or use the classes as is to provide sorting functionality.

    [186] TableMap.java and TableSorter.java are on the CD at: JavaTutorial/uiswing/components/example-1dot4/TableSorterDemo.java.



    To implement sorting with TableSorter, you need just three lines of code. The following listing shows the differences between TableDemo and its sorting cousin, TableSorterDemo.[187]

    [187] TableMap.java and TableSorterDemo.java are on the CD at: JavaTutorial/uiswing/components/example-1dot4/index.html#TableSorterDemo.





    TableSorter sorter = new TableSorter(new MyTableModel()); //ADDED THIS

    //JTable table = new JTable(new MyTableModel()); //OLD

    JTable table = new JTable(sorter); //NEW

    sorter.addMouseListenerToHeaderInTable(table); //ADDED THIS



    The addMouseListenerToHeaderInTable method adds a mouse listener that detects clicks over the column headers. When the listener detects a click, it sorts the rows based on the clicked column. As Figure 83 shows, when you click "Last Name," the rows are reordered so that "Campione" is in the first row and "Zakhour" is in the last. When you Shift-click a column header, the rows are sorted in reverse order.



    Figure 83. The TableSorterDemo application with the Last Name column sorted alphabetically.




    The Table API



    Tables 88 through 92 cover just part of the table API. For more information about the table API, see the API documentation for JTable[188] and for the various classes and interfaces in the table package.[189] Also see The JComponent Class (page 53), which describes the API that JTable inherits from JComponent.

    [188] JTable API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JTable.html.

    [189] Table package API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/table/package-summary.html.



    Table 88. Table-Related Classes and Interfaces

    Class or Interface

    Purpose

    JTable

    The component that presents the table to the user.

    JTableHeader

    The component that presents the column names to the user. By default, the table generates this component automatically.





    TableModel

    AbstractTableModel

    Respectively, the interface that a table model must implement and the usual superclass for table model implementations.





    TableCellRenderer

    DefaultTableCellRenderer

    Respectively, the interface that a table cell renderer must implement and the usual implementation used.





    TableCellEditor

    DefaultCellEditor

    AbstractCellEditor

    Respectively, the interface that a table cell editor must implement, the usual implementation used, and the usual superclass for table cell editor implementations.





    TableColumnModel

    DefaultTableColumnModel

    Respectively, the interface that a table column model must implement and the usual implementation used. You don't usually need to deal with the table column model directly unless you need to get the column selection model, or get a column index or object.

    TableColumn

    Controls all the attributes of a table column, including resizability; minimum, preferred, current, and maximum widths; and an optional column-specific renderer/editor.

    DefaultTableModel

    A Vector-based table model used by JTable when you construct a table specifying no data model and no data.

    TableModelListener

    The interface that an object must implement to be notified of changes to the TableModel.

    ListSelectionListener

    The interface that an object must implement to be notified of changes to the table's selection.



    Table 89. Creating and Setting up a Table

    Constructor or Method

    Purpose





    JTable(TableModel)

    JTable(TableModel, TableColumnModel)

    JTable(TableModel,

    TableColumnModel,

    ListSelectionModel)

    JTable()

    JTable(int, int)

    JTable(Object[][], Object[])

    JTable(Vector, Vector)

    Create a table. The optional TableModel argument specifies the model that provides the data to the table. The optional TableColumnModel and ListSelectionModel arguments let you specify the table column model and the row selection model. As an alternative to specifying a table model, you can supply data and column names, using arrays or vectors. Another option is to specify no data, optionally specifying the number of rows and columns (both integers) to be in the table.





    void setPreferredScrollableViewportSize(

    Dimension)

    Set the size of the visible part of the table when it's viewed within a scroll pane.

    JTableHeader getTableHeader()

    Get the component that displays the column names.



    Table 90. Manipulating Columns

    Constructor or Method

    Purpose





    TableColumnModel getColumnModel()

    (in JTable)

    Get the table's column model.





    TableColumn getColumn(int)

    Enumeration getColumns()

    (in TableColumnModel)

    Get one or all of the TableColumn objects for the table.





    void setMinWidth(int)

    void setPreferredWidth(int)

    void setMaxWidth(int)

    (in TableColumn)

    Set the minimum, preferred, or maximum width of the column.





    int getMinWidth()

    int getPreferredWidth()

    int getMaxWidth()

    int getWidth()

    (in TableColumn)

    Get the minimum, preferred, maximum, or current width of the column.



    Table 91. Using Editors and Renderers

    Method

    Purpose





    void setDefaultRenderer(Class,

    TableCellRenderer)

    void setDefaultEditor(Class,

    TableCellEditor)

    (in JTable)

    Set the renderer or editor used, by default, for all cells in all columns that return objects of the specified type.





    void setCellRenderer(TableCellRenderer)

    void setCellEditor(TableCellEditor)

    (in TableColumn)

    Set the renderer or editor used for all cells in this column.





    TableCellRenderer getHeaderRenderer()

    (in TableColumn)

    Get the header renderer for this column.



    Version Note:

    As of 1.3, this method returns null if the column uses the default renderer. You generally use the TableHeader method getDefaultRenderer instead.





    TableCellRenderer getDefaultRenderer()

    (in JTableHeader)

    Get the header renderer used when none is defined by a table column. Introduced in 1.3.



    Table 92. Implementing Selection

    Method

    Purpose

    void setSelectionMode(int)

    Set the selection intervals allowed in the table. Valid values are defined in ListSelectionModel as SINGLE_SELECTION, SINGLE_INTERVAL_SELECTION, and MULTIPLE_INTERVAL_SELECTION (the default).





    void setSelectionModel(ListSelectionModel)

    ListSelectionModel getSelectionModel()

    Set or get the model used to control row selections.





    void setRowSelectionAllowed(boolean)

    void setColumnSelectionAllowed(boolean)

    void setCellSelectionEnabled(boolean)

    Set the table's selection orientation. The boolean argument specifies whether that particular type of selection is allowed. By default, row selection is allowed, and column and cell selection are not.



    Examples That Use Tables



    This table lists examples that use JTable and where those examples are described.



    Example

    Where Described

    Notes

    SimpleTableDemo

    Creating a Simple Table (page 388)

    A basic table with no custom model. Does not include code to specify column widths or detect user editing.

    SimpleTableSelectionDemo

    Detecting User Selections (page 393)

    Adds single selection and selection detection to SimpleTableDemo. By modifying the program's ALLOW_COLUMN_SELECTION and ALLOW_ROW_SELECTION constants, you can experiment with alternatives to the table default of allowing only rows to be selected.

    TableDemo

    Creating a Table Model (page 394)

    A basic table with a custom model.

    TableFTFEditDemo

    Using an Editor to Validate User-Entered Text (page 401)

    Modifies TableDemo to use a custom editor (a formatted text field variant) for all Integer data.

    TableRenderDemo

    Using a Combo Box as an Editor (page 400)

    Modifies TableDemo to use a custom editor (a combo box) for all data in the Sport column. Also intelligently picks column sizes. Uses renderers to display tool tips for the Sport cells.

    TableDialogEditDemo

    Using Other Editors (page 402)

    Modifies TableDemo to have a cell renderer and editor that display a color and let you choose a new one, using a color chooser dialog.

    TableToolTipsDemo

    Specifying Tool Tips for Cells (page 407), Specifying Tool Tips for Column Headers (page 410)

    Demonstrates how to use several techniques to set tool tip text for cells and column headers.

    TableSorterDemo

    Sorting and Otherwise Manipulating Data (page 412)

    Sorts column data by interposing a data-manipulating table model between the data model and the table. Detects user clicks on column headers.

    ListSelectionDemo

    How to Write a List Selection Listener (page 685)

    Shows how to use all list selection modes, using a list selection listener that's shared between a table and list.

    SharedModelDemo

    Using Models (page 50)

    Builds on ListSelectionDemo, making the data model be shared between the table and list. If you edit an item in the first column of the table, the new value is reflected in the list.





    TreeTable

    TreeTable II

    "Creating TreeTables in Swing" (Parts 1, 2 and 3) in The Swing Connection, online at: http://java.sun.com/products/jfc/tsc/articles/treetable1/index.html.

    Examples that combine a tree and table to show detailed information about a hierarchy such as a file system. The tree is a renderer for the table.













       < Day Day Up > 



      Newer Posts Older Posts Home