UML - How to align class diagrams with child classes verticaly - uml

In the attached UML diagram are 5 classes and I want to find out how the top of classes A,B and C can be verticaly aligned while the child classes remain aligned. Please find my UML code and my screenshots below.
Tanks a lot for your support ! :)
What it looks currently like:
How it should look like (paint edited):
UML - code:
#startuml TestClassDiagram
scale 800 width
skinparam SameClassWidth true
skinparam ClassFontSize 15
class classA {
{field} - attribute1 : int
{field} - attribute2 : int
{method} + method1(void)
{method} + method2(void)
{method} + method3(void)
{method} + method4(void)
{method} + method5(void)
}
class classB {
{field} - attribute1 : int
{field} - attribute2 : int
{method} + method1(void)
{method} + method2(void)
}
class classBchild {
{method} + method1(void)
}
class classC {
{field} - attribute1 : int
{field} - attribute2 : int
{field} - attribute3 : int
{field} - attribute4 : int
{method} + method1(void)
{method} + method2(void)
{method} + method3(void)
{method} + method4(void)
{method} + method5(void)
}
class classCchild {
{method} + method1(void)
}
classB <|-- classBchild
classC <|-- classCchild
#enduml

There isn't a feature to align classes in PlantUML (yet).
If we add arrows between all elements, it is clear to see wht PlantUML is trying to do:
It is simply aligning all diagrams from the middle.
using this, we can create a hack that sort of achieves the result you want by padding the class definition with extra newlines until they are all the same size:
#startuml
skinparam {
SameClassWidth true
ClassFontSize 15
}
class A as "classA" {
{field} - attribute1 : int
{field} - attribute2 : int
__
{method} + method1(void)
{method} + method2(void)
{method} + method3(void)
{method} + method4(void)
{method} + method5(void)
}
class B as "classB" {
{field} - attribute1 : int
{field} - attribute2 : int
__
{method} + method1(void)
{method} + method2(void)
}
class Bc as "classBchild" {
{method} + method1(void)
}
class C as "classC" {
{field} - attribute1 : int
{field} - attribute2 : int
{field} - attribute3 : int
{field} - attribute4 : int
{method} + method1(void)
{method} + method2(void)
{method} + method3(void)
{method} + method4(void)
{method} + method5(void)
}
class Cc as "classCchild" {
{method} + method1(void)
}
B <|-- Bc
C <|-- Cc
#enduml

Related

servicestack null ref error when using native SQL and ORMLite. Dapper error

I am getting an error trying to get this data with ORMLite. I am pretty sure its failing because the ParentID is null. But I don't know how to fix it.
It errors when I call this method.
return Db.Query<GetCompaniesById>("select * FROM [Company];");
It works fine if I call it with
var q = Db.From<Company>(Db.TableAlias("c1"))
.Join<Company>((ChildComp, ParentCompany) =>
ChildComp.Id == ParentCompany.ParentId
&& ParentCompany.Id == request.Id, Db.TableAlias("c2")).Select<Company>(p => new {Id = Sql.TableAlias(p.Id, "c2"), Name = Sql.TableAlias(p.Name, "c2")});
The error
+ $exception {System.Data.DataException: Error parsing column 3 (ParentId=1 - Int64) ---> System.InvalidCastException: Unable to cast object of type 'System.Int64' to type 'System.Nullable`1[System.Int32]'.
at Deserializea4b39d89-32a6-4a82-89cf-2e520c205673(IDataReader )
--- End of inner exception stack trace ---
at ServiceStack.OrmLite.Dapper.SqlMapper.ThrowDataException(Exception ex, Int32 index, IDataReader reader, Object value)
at Deserializea4b39d89-32a6-4a82-89cf-2e520c205673(IDataReader )
at ServiceStack.OrmLite.Dapper.SqlMapper.QueryImpl[T](IDbConnection cnn, CommandDefinition command, Type effectiveType)+MoveNext()
at System.Collections.Generic.List`1.AddEnumerable(IEnumerable`1 enumerable)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at ServiceStack.OrmLite.Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable`1 commandTimeout, Nullable`1 commandType)
at cbw.service.interfaces.Services.CompanyService.Get(GetCompaniesById request)
at ServiceStack.Host.ServiceRunner`1.ExecuteAsync(IRequest req, Object instance, TRequest requestDto)} System.Data.DataException
public class Company : DTOServiceStackBase
{
[AutoIncrement]
[PrimaryKey]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public string Address { get; set; }
public int? ParentId { get; set; }
[IgnoreDataMember]
public List<Company> SubCompanies { get; set; }
}
[Route("/Company/{Id}", "GET")]
public class GetCompaniesById : IReturn<GetCompaniesById>
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public int? ParentId { get; set; }
public string NotVisible => "Id,ParentId";
}
private void CompanyInit()
{
int val = 0;
using (var db = Db)
{
db.CreateTable<Company>();
db.Insert(new Company { Name = "Top Company A" + val++});//1 - Top Company Don't Add Parent ID
db.Insert(new Company { Name = "Company B" + val++, ParentId = 1 });//2
db.Insert(new Company { Name = "Company C" + val++, ParentId = 2 });//3
db.Insert(new Company { Name = "Company D" + val++, ParentId = 3 });//4
db.Insert(new Company { Name = "Company E" + val++, ParentId = 1 });//5
db.Insert(new Company { Name = "Company F" + val++, ParentId = 1 });//6
db.Insert(new Company { Name = "Company G" + val++, ParentId = 1 });//7
db.Insert(new Company { Name = "Company H" + val++, ParentId = 1 });//8
db.Insert(new Company { Name = "Company I" + val++, ParentId = 17 });//9
db.Insert(new Company { Name = "Company J" + val++, ParentId = 4 });//10
db.Insert(new Company { Name = "Company K" + val++, ParentId = 10 });//11
db.Insert(new Company { Name = "Company L" + val++, ParentId = 11 });//12
db.Insert(new Company { Name = "Company M" + val++, ParentId = 2 });//13
db.Insert(new Company { Name = "Company N" + val++, ParentId = 13 });//14
db.Insert(new Company { Name = "Company O" + val++, ParentId = 14 });//15
db.Insert(new Company { Name = "Company P" + val++, ParentId = 15 });//16
db.Insert(new Company { Name = "Company Q" + val++, ParentId = 16 });//17
db.Insert(new Company { Name = "Company R" + val++, ParentId = 17 });//18
//validation it works
var result = db.SingleById<Company>(1);
result.PrintDump(); //= {Id: 1, Name:Seed Data}
}
}
Have you tried just using OrmLite's SqlList to execute custom SQL?
var results = Db.SqlList<GetCompaniesById>("select * FROM [Company];");
Or a typed version with:
var results = Db.Select<GetCompaniesById>(Db.From<Company>());
With specific fields:
var results = Db.Select<GetCompaniesById>(Db.From<Company>()
.Select(x => new { x.Id, X.Name, X.Address, x.ParentId }));
An alternative option is to use your existing Company data model then use the Auto Mapping Utils to map it to your preferred type:
var results = Db.Select<Company>();
var dtos = results.Map(x => x.ConvertTo<GetCompaniesById>());

Antlr4 param-value parsing

I'm new to antlr and trying to parse a file of mine (IBM Datastage export).
I have a working grammar but i'm not fully satisfied and I'm not sure I'm using antlr the right way :(
Here is an example of source file :
BEGIN HEADER
CharacterSet "CP1252"
ExportingTool "IBM InfoSphere DataStage Export"
ToolVersion "8"
ServerName "MIAIBV240"
ToolInstanceID "DFDMGBL2"
MDISVersion "1.0"
Date "2018-02-12"
Time "17.32.28"
ServerVersion "8.7"
END HEADER
BEGIN DSJOB
Identifier "job_FDM_WVD_NET_SALES_DSC_STG_REPL_Load"
DateModified "2018-02-12"
TimeModified "17.32.24"
BEGIN DSRECORD
Identifier "C52"
OLEType "CContainerStage"
Readonly "0"
Name "ShcFileAudit_Verif_Data"
NextID "3"
BEGIN DSSUBRECORD
Name "FDM_CMN"
Description "#FDM_CMN#"
ValueType "0"
END DSSUBRECORD
BEGIN DSSUBRECORD
Name "FILE_NAME"
FullDescription =+=+=+=#------------------------------------------------------------------------------- Description:
Some desc here ....
# Date Issue Version
=+=+=+=
JobVersion "56.0.0"
ControlAfterSubr "0"
Parameters "CParameters"
END DSSUBRECORD
END DSRECORD
END DSJOB
As you can see it is mostly Key/value pairs.
I use this grammar :
grammar dsxGrammar;
dsxFile : headerDeclaration? jobDeclaration* EOF;
headerDeclaration : BEGIN HEADER paramHeader* END HEADER;
jobDeclaration : BEGIN DSJOB paramJob* recordDeclaration* paramJob* END DSJOB;
recordDeclaration : BEGIN DSRECORD (paramRecord | subrecordDeclaration )* END DSRECORD;
subrecordDeclaration : BEGIN DSSUBRECORD paramSubRecord* END DSSUBRECORD;
paramHeader : PNAME PVALUE;
paramJob : PNAME PVALUE;
paramRecord : PNAME PVALUE;
paramSubRecord : PNAME PVALUE;
//PVALUE : '"' Text '"';
PVALUE : '"' .*? '"';
BEGIN : 'BEGIN';
END : 'END';
HEADER : 'HEADER';
DSJOB : 'DSJOB';
DSRECORD : 'DSRECORD';
DSSUBRECORD : 'DSSUBRECORD';
ORCHCODE : 'OrchestrateCode =+=+=+=' .*? '=+=+=+=' -> skip;
FULLDESC : 'FullDescription =+=+=+=' .*? '=+=+=+=' -> skip;
VALUECODE : 'Value =+=+=+=' .*? '=+=+=+=' -> skip;
EXPRCODE : 'Expression =+=+=+=' .*? '=+=+=+=' -> skip;
DERIVCODE : 'Derivation =+=+=+=' .*? '=+=+=+=' -> skip;
WS : [ \t\r\n\u000C]+ -> skip;
SPACE : ' ';
COMMENT : '/*' .*? '*/' -> skip;
LINE_COMMENT : '//' ~[\r\n]* -> skip;
//Identifier : NONDIGIT ( NONDIGIT | DIGIT)*;
fragment Text : NONDIGIT ( SPACE | NONDIGIT | DIGIT)*;
fragment NONDIGIT : [a-zA-Z_] ;
fragment DIGIT : [0-9];
PNAME : ~["\\ \t\r\n]+;
It's working but i have to parse PNAME and PVALUE afterwards in my python code to extract double quotes, etc...
Is it the right way to do or I can do something with a Text fragment ?
I would like to have access to HeadProperty.PNAME and HeadProperty.PVALUE for example.
Thanks for your help !
[...] Is it the right way to do or I can do something with a Text fragment ?
Not in the grammar (at least, not without using target specific code). You'll have to change the text in a listener or visitor. In your case, I'd go for a visitor. The code below is in Java, but should be easily converted to Python.
First a couple of remarks about your current grammar:
lexer rules like these 'OrchestrateCode =+=+=+=' can be fragile. If the input contains something like this: OrchestrateCode =+=+=+= (2 spaces), it won't be tokenised properly
your rule SPACE : ' '; is only used in a fragment, so it should also be a fragment
you're repeating PNAME PVALUE quite a lot in your parser rules: I'd create a keyValues rule for it (this also simplifies the visitor which I'll add below)
the same for =+=+=+= in your lexer rule: I'd create a fragment that matches this (DRY!)
It looks like a lot of feedback, but they're all minor points. Given that you're new to ANTLR, I think you did a good job.
OK, given the points above, your grammar could look like this:
grammar dsxGrammar;
dsxFile : headerDeclaration? jobDeclaration* EOF;
headerDeclaration : BEGIN HEADER paramHeaders=keyValues END HEADER;
jobDeclaration : BEGIN DSJOB paramJob+=keyValues recordDeclaration* paramJob+=keyValues END DSJOB;
recordDeclaration : BEGIN DSRECORD ( paramRecord+=keyValue | subrecordDeclaration )* END DSRECORD;
subrecordDeclaration : BEGIN DSSUBRECORD paramSubRecords=keyValues END DSSUBRECORD;
keyValues : keyValue*;
keyValue : PNAME PVALUE;
PVALUE : '"' .*? '"';
BEGIN : 'BEGIN';
END : 'END';
HEADER : 'HEADER';
DSJOB : 'DSJOB';
DSRECORD : 'DSRECORD';
DSSUBRECORD : 'DSSUBRECORD';
ORCHCODE : 'OrchestrateCode' SPACE* SEPARATOR .*? SEPARATOR -> skip;
FULLDESC : 'FullDescription' SPACE* SEPARATOR .*? SEPARATOR -> skip;
VALUECODE : 'Value' SPACE* SEPARATOR .*? SEPARATOR -> skip;
EXPRCODE : 'Expression' SPACE* SEPARATOR .*? SEPARATOR -> skip;
DERIVCODE : 'Derivation' SPACE* SEPARATOR .*? SEPARATOR -> skip;
WS : SPACE+ -> skip;
COMMENT : '/*' .*? '*/' -> skip;
LINE_COMMENT : '//' ~[\r\n]* -> skip;
PNAME : ~["\\ \t\r\n]+;
fragment NONDIGIT : [a-zA-Z_] ;
fragment DIGIT : [0-9];
fragment SPACE : [ \t\r\n\u000C];
fragment SEPARATOR : '=+=+=+=';
You might notice the labels in the parser rules, like paramSubRecords=... and paramJob+=.... These are good for 2 things:
readability of your grammar (keyValues doesn't mean much, while it's clear what keyValues really is in case paramSubRecords=keyValues is written)
in your listener or visitor, you can reference these labeled children from a parent context. Say you have the rule
foo : first=PNAME second=PNAME;
then you can do this in a visitor:
#Override
public Object visitFoo(dsxGrammarParser.FooContext ctx) {
String firstName = ctx.first.getText();
String secondName = ctx.second.getText();
...
}
And if you have a += in there like this:
foo : allJobs+=jobDeclaration+ PNAME allJobs+=jobDeclaration+;
then all jobDeclaration contexts are added in a java.util.List you can use in the parent context:
#Override
public Object visitFoo(dsxGrammarParser.FooContext ctx) {
List<dsxGrammarParser.JobDeclarationContext> jobs = ctx.allJobs;
...
}
If you now generate a visitor from the updated grammar, you can test it like this:
public class Main {
public static void main(String[] args) {
String source = "BEGIN HEADER\n" +
" CharacterSet \"CP1252\"\n" +
" ExportingTool \"IBM InfoSphere DataStage Export\"\n" +
" ToolVersion \"8\"\n" +
" ServerName \"MIAIBV240\"\n" +
" ToolInstanceID \"DFDMGBL2\"\n" +
" MDISVersion \"1.0\"\n" +
" Date \"2018-02-12\"\n" +
" Time \"17.32.28\"\n" +
" ServerVersion \"8.7\"\n" +
"END HEADER\n" +
"BEGIN DSJOB\n" +
" Identifier \"job_FDM_WVD_NET_SALES_DSC_STG_REPL_Load\"\n" +
" DateModified \"2018-02-12\"\n" +
" TimeModified \"17.32.24\"\n" +
" BEGIN DSRECORD\n" +
" Identifier \"C52\"\n" +
" OLEType \"CContainerStage\"\n" +
" Readonly \"0\"\n" +
" Name \"ShcFileAudit_Verif_Data\"\n" +
" NextID \"3\"\n" +
" BEGIN DSSUBRECORD\n" +
" Name \"FDM_CMN\"\n" +
" Description \"#FDM_CMN#\"\n" +
" ValueType \"0\"\n" +
" END DSSUBRECORD\n" +
" BEGIN DSSUBRECORD\n" +
" Name \"FILE_NAME\"\n" +
" FullDescription =+=+=+=#------------------------------------------------------------------------------- Description:\n" +
"\n" +
"Some desc here .... \n" +
"# Date Issue Version \n" +
"=+=+=+=\n" +
" JobVersion \"56.0.0\"\n" +
" ControlAfterSubr \"0\"\n" +
" Parameters \"CParameters\"\n" +
" END DSSUBRECORD\n" +
"END DSRECORD\n" +
"END DSJOB";
dsxGrammarLexer lexer = new dsxGrammarLexer(CharStreams.fromString(source));
dsxGrammarParser parser = new dsxGrammarParser(new CommonTokenStream(lexer));
DsxFile dsxFile = new MapVisitor().visitDsxFile(parser.dsxFile());
System.out.println(dsxFile);
}
}
class MapVisitor extends dsxGrammarBaseVisitor<Object> {
// dsxFile : headerDeclaration? jobDeclaration* EOF;
#Override
public DsxFile visitDsxFile(dsxGrammarParser.DsxFileContext ctx) {
Map<String, String> headerDeclaration = visitHeaderDeclaration(ctx.headerDeclaration());
List<JobDeclaration> jobDeclarations = new ArrayList<>();
if (ctx.jobDeclaration() != null) {
for (dsxGrammarParser.JobDeclarationContext child : ctx.jobDeclaration()) {
jobDeclarations.add(visitJobDeclaration(child));
}
}
return new DsxFile(headerDeclaration, jobDeclarations);
}
// headerDeclaration : BEGIN HEADER paramHeaders=keyValues END HEADER;
#Override
public Map<String, String> visitHeaderDeclaration(dsxGrammarParser.HeaderDeclarationContext ctx) {
return visitKeyValues(ctx.paramHeaders);
}
// jobDeclaration : BEGIN DSJOB paramJob+=keyValues recordDeclaration* paramJob+=keyValues END DSJOB;
#Override
public JobDeclaration visitJobDeclaration(dsxGrammarParser.JobDeclarationContext ctx) {
Map<String, String> paramJobs = new LinkedHashMap<>();
List<RecordDeclaration> recordDeclarations = new ArrayList<>();
for (dsxGrammarParser.KeyValuesContext child : ctx.paramJob) {
paramJobs.putAll(visitKeyValues(child));
}
for (dsxGrammarParser.RecordDeclarationContext child : ctx.recordDeclaration()) {
recordDeclarations.add(visitRecordDeclaration(child));
}
return new JobDeclaration(paramJobs, recordDeclarations);
}
// recordDeclaration : BEGIN DSRECORD ( paramRecord+=keyValue | subrecordDeclaration )* END DSRECORD;
#Override
public RecordDeclaration visitRecordDeclaration(dsxGrammarParser.RecordDeclarationContext ctx) {
Map<String, String> paramRecords = new LinkedHashMap<>();
List<Map<String, String>> subrecordDeclarations = new ArrayList<>();
for (dsxGrammarParser.KeyValueContext child : ctx.paramRecord) {
String[] keyValue = visitKeyValue(child);
paramRecords.put(keyValue[0], keyValue[1]);
}
for (dsxGrammarParser.SubrecordDeclarationContext child : ctx.subrecordDeclaration()) {
subrecordDeclarations.add(visitSubrecordDeclaration(child));
}
return new RecordDeclaration(paramRecords, subrecordDeclarations);
}
// subrecordDeclaration : BEGIN DSSUBRECORD paramSubRecords=keyValues END DSSUBRECORD;
#Override
public Map<String, String> visitSubrecordDeclaration(dsxGrammarParser.SubrecordDeclarationContext ctx) {
return visitKeyValues(ctx.paramSubRecords);
}
// keyValues : keyValue*;
#Override
public Map<String, String> visitKeyValues(dsxGrammarParser.KeyValuesContext ctx) {
Map<String, String> map = new LinkedHashMap<>();
if (ctx.keyValue() != null) {
for (dsxGrammarParser.KeyValueContext child : ctx.keyValue()) {
String[] keyValue = visitKeyValue(child);
map.put(keyValue[0], keyValue[1]);
}
}
return map;
}
// keyValue : PNAME PVALUE;
#Override
public String[] visitKeyValue(dsxGrammarParser.KeyValueContext ctx) {
return new String[] {
ctx.PNAME().getText(),
ctx.PVALUE().getText().substring(1, ctx.PVALUE().getText().length() - 1)
};
}
}
// headerDeclaration? jobDeclaration* EOF
class DsxFile {
final Map<String, String> headerDeclaration;
final List<JobDeclaration> jobDeclarations;
DsxFile(Map<String, String> headerDeclaration, List<JobDeclaration> jobDeclarations) {
this.headerDeclaration = headerDeclaration;
this.jobDeclarations = jobDeclarations;
}
#Override
public String toString() {
return "DsxFile{" +
"\n headerDeclaration=" + headerDeclaration +
"\n jobDeclarations=" + jobDeclarations +
"\n}";
}
}
// BEGIN DSJOB paramJob+=keyValues recordDeclaration* paramJob+=keyValues END DSJOB
class JobDeclaration {
final Map<String, String> paramJobs;
final List<RecordDeclaration> recordDeclarations;
JobDeclaration(Map<String, String> paramJobs, List<RecordDeclaration> recordDeclarations) {
this.paramJobs = paramJobs;
this.recordDeclarations = recordDeclarations;
}
#Override
public String toString() {
return "\n JobDeclaration{" +
"\n paramJobs=" + paramJobs +
"\n recordDeclarations=" + recordDeclarations +
"\n }";
}
}
// BEGIN DSRECORD ( paramRecord+=keyValue | subrecordDeclaration )* END DSRECORD
class RecordDeclaration {
final Map<String, String> paramRecords;
final List<Map<String, String>> subrecordDeclarations;
RecordDeclaration(Map<String, String> paramRecords, List<Map<String, String>> subrecordDeclarations) {
this.paramRecords = paramRecords;
this.subrecordDeclarations = subrecordDeclarations;
}
#Override
public String toString() {
return "\n RecordDeclaration{" +
"\n paramRecords=" + paramRecords +
"\n subrecordDeclarations=" + subrecordDeclarations +
"\n }";
}
}
If you run the main class, you'll see the following being printed to your console:
DsxFile{
headerDeclaration={CharacterSet=CP1252, ExportingTool=IBM InfoSphere DataStage Export, ToolVersion=8, ServerName=MIAIBV240, ToolInstanceID=DFDMGBL2, MDISVersion=1.0, Date=2018-02-12, Time=17.32.28, ServerVersion=8.7}
jobDeclarations=[
JobDeclaration{
paramJobs={Identifier=job_FDM_WVD_NET_SALES_DSC_STG_REPL_Load, DateModified=2018-02-12, TimeModified=17.32.24}
recordDeclarations=[
RecordDeclaration{
paramRecords={Identifier=C52, OLEType=CContainerStage, Readonly=0, Name=ShcFileAudit_Verif_Data, NextID=3}
subrecordDeclarations=[{Name=FDM_CMN, Description=#FDM_CMN#, ValueType=0}, {Name=FILE_NAME, JobVersion=56.0.0, ControlAfterSubr=0, Parameters=CParameters}]
}]
}]
}

Passing Objects through Heap Sort

Having issues trying to pass an object class to be sorted via Heap Sort. Basically I have a class which holds employee data such as names, address, phone numbers and employee ID. We are to use Heap Sort to pass this class as a object and sort it by employee ID. My main issue is converting my heap sort structures to where they can take objects. This is for a beginning data structures course so we're not allowed to use advanced techniques. My road block is I'm stumped as to how to pass my objects into the heap sort methods which currently only take primitive data types.
Office Class:
public class Office_Staff
{
public String Name , Dept , Phonenumber;
public int Id, years;
Office_Staff()
{
Id = ("");
Name = ("");
Dept = ("");
Phonenumber = ("");
years = 0;
}
Office_Staff(int empid ,String empname, String empdept , String empphone, int service)
{
Id = empid;
Name = empname;
Dept = empdept;
Phonenumber = empphone;
years = service;
}
public void setId(int empid)
{
Id = empid;
}
public void setName(String empname)
{
Name = empname;
}
public void setDept(String empdept)
{
Dept = empdept;
}
public void setPhone(String empphone)
{
Phonenumber = empphone;
}
public void setYears(int service)
{
years = service;
}
public String getId()
{
return Id;
}
public String getName()
{
return Name;
}
public String getDept()
{
return Dept;
}
public String getPhone()
{
return Phonenumber;
}
public int getYears()
{
return years;
}
public String toString()
{
String str = "Office_Staff Name : " + Name + "Office_Staff ID : " + Id +
"Office_Staff Deaprtment : " + Dept + "Office_Staff Phone Number : "
+ Phonenumber + "Years Active : " + years;
return str;
}
}
Heap Sort:
import java.util.Scanner;
import java.util.ArrayList;
import java.io.*;
class zNode
{
private int iData;
public zNode(int key)
{
iData = key;
}
public int getKey()
{
return iData;
}
public void setKey(int k)
{
iData = k;
}
}
class HeapSort
{
private int [] currArray;
private int maxSize;
private int currentSize;
private int currIndex;
HeapSort(int mx)
{
maxSize = mx;
currentSize = 0;
currArray = new int[maxSize];
}
//buildheap
public boolean buildHeap(int [] currArray)
{
int key = currIndex;
if(currentSize==maxSize)
return false;
int newNode = key;
currArray[currentSize] = newNode;
siftUp(currArray , currentSize++);
return true;
}
//siftup
public void siftUp(int [] currArray , int currIndex)
{
int parent = (currIndex-1) / 2;
int bottom = currArray[currIndex];
while( currIndex > 0 && currArray[parent] < bottom )
{
currArray[currIndex] = currArray[parent];
currIndex = parent;
parent = (parent-1) / 2;
}
currArray[currIndex] = bottom;
}
//siftdown
public void siftDown(int [] currArray , int currIndex)
{
int largerChild;
int top = currArray[currIndex];
while(currIndex < currentSize/2)
{
int leftChild = 2*currIndex+1;
int rightChild = leftChild+1;
if(rightChild < currentSize && currArray[leftChild] < currArray[rightChild] )
largerChild = rightChild;
else
largerChild = leftChild;
if( top >= currArray[largerChild] )
break;
currArray[currIndex] = currArray[largerChild];
currIndex = largerChild;
}
currArray[currIndex] = top;
}
//remove max element
public int removeMaxElement(int [] currArray)
{
int root = currArray[0];
currArray[0] = currArray[--currentSize];
siftDown(currArray , 0);
return root;
}
//heapsort
private void _sortHeapArray(int [] currArray)
{
while(currentSize != 0)
{
removeMaxElement(currArray);
}
}
public void sortHeapArray()
{
_sortHeapArray(currArray);
}
//hepify
private int[] heapify(int[] currArray)
{
int start = (currentSize) / 2;
while (start >= 0)
{
siftDown(currArray, start);
start--;
}
return currArray;
}
//swap
private int[] swap(int[] currArray, int index1, int index2)
{
int swap = currArray[index1];
currArray[index1] = currArray[index2];
currArray[index2] = swap;
return currArray;
}
//heapsort
public int[] _heapSort(int[] currArray)
{
heapify(currArray);
int end = currentSize-1;
while (end > 0)
{
currArray = swap(currArray,0, end);
end--;
siftDown(currArray, end);
}
return currArray;
}
public void heapSort()
{
_heapSort(currArray);
}

BlackBerry 6/7 Table Layout with ColSpan - Number Selection Widget

Trying to make a simple number clicker control for BlackBerry 6/7, like this:
At heart it's just a text field and two buttons, with a Manager to space them out.
I know about the unsupported add-on TableManager, but it doesn't support column scans. And, the notion of using deeply-nested Managers I find... disturbing.
And, this will come up multiple times, so I wanted a simple, reusable component.
So, I built a simple Manager to contain these three components, even allowing you to provide your own textfield or buttons for stylistic reasons. The code is attached below. Obviously fancier than it needs to be but the work is all done in sublayout.
What actually happens is that the upper right of each of the 3 components appears in the correct place, but the 3 components are "shrink wrapped" to the minimum size needed to display their contents, ignoring the requested USE_ALL_WIDTH and USE_ALL_HEIGHT. This is probably a minor goofup, but how can I make these components actually USE ALL WIDTH and USE ALL HEIGHT? I have tried several variations on USE_ALL_* but not found the winning one yet. Of course any other improvements would also be welcome.
Thanks.
package layout;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.XYEdges;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.EditField;
/**
* XXX BROKEN DO NOT USE YET - layout fail, components get shrink-wrapped.
*
* NumberClicker Makes a layout with three components, like this:
* <pre>
* +-------------------+ +-------------------+
* | | | + |
* | 3 | |-------------------|
* | | |-------------------|
* | | | - |
* |-------------------| |-------------------|
* </pre>
* Note that by default, the buttons are set to increment and decrement the number in the textfield!
* #author Ian Darwin
*/
public class NumberClicker extends Manager {
private static final long SUBCOMPONENT_STYLE = Field.USE_ALL_HEIGHT | Field.USE_ALL_WIDTH;
private static final long MANAGER_STYLE = Field.FIELD_HCENTER | Field.FIELD_VCENTER;
final XYEdges MARGINS = new XYEdges(10,10,10,10);
EditField number = new EditField(SUBCOMPONENT_STYLE);
ButtonField plus = new ButtonField("+", SUBCOMPONENT_STYLE);
ButtonField minus = new ButtonField("-", SUBCOMPONENT_STYLE);
public NumberClicker() {
this(MANAGER_STYLE);
}
public NumberClicker(long style)
{
this(null, null, null, style);
}
/** Constructor allows you to provide your own three fields */
public NumberClicker(EditField number, ButtonField plus, ButtonField minus) {
this(number, plus, minus, MANAGER_STYLE);
}
/** Constructor allows you to provide your own three fields ANd override style.
* If any of the fields is null, the default value is used.
*/
public NumberClicker(EditField number, ButtonField plus, ButtonField minus, long style) {
super(style);
if (number != null) {
this.number = number;
} else {
this.number.setMargin(MARGINS); // set margins on our default, constructed above.
}
setValue(1);
add(this.number); // Nulls allowed, so must be careful to use "this." throughout this method.
if (plus != null) {
this.plus = plus;
} else {
this.plus.setMargin(MARGINS);
}
add(this.plus);
if (minus != null) {
this.minus = minus;
} else {
this.minus.setMargin(MARGINS);
}
add(this.minus);
this.plus.setRunnable(new Runnable() {
public void run() {
increment();
}
});
this.minus.setRunnable(new Runnable() {
public void run() {
decrement();
}
});
}
public void increment() {
number.setText(Integer.toString(Integer.parseInt(number.getText().trim()) + 1));
}
public void decrement() {
number.setText(Integer.toString(Integer.parseInt(number.getText().trim()) - 1));
}
/** Return the integer value of the clicker. Do not call if you are re-using this as a three-component layout manager! */
public int getValue() {
return Integer.parseInt(number.getText().trim());
}
public void setValue(int value) {
number.setText(Integer.toString(value));
}
/**
* Compute sizes and positions of subfields.
*
* Required by Manager
*/
public void sublayout(int width, int height) {
int layoutWidth = width;
int layoutHeight = Math.min(height, Display.getHeight()); // no scrolling here
System.err.println("Display:" + Display.getWidth() + "x" + Display.getHeight());
int halfX = layoutWidth / 2;
int halfY = layoutHeight / 2;
System.err.println("sublayout:" + width + "," + height + "; " + halfX + "," + halfY);
int numberWidth = halfX - number.getMarginLeft() - number.getMarginRight();
int numberHeight = layoutHeight - number.getMarginTop() - number.getMarginBottom();
layoutChild(number, numberWidth, numberHeight);
setPositionChild(number, 0 + number.getMarginLeft(), 0 + number.getMarginTop());
System.err.println(number + " " + numberWidth + "," + numberHeight + " " +number.getMarginLeft());
int plusWidth = halfX - plus.getMarginLeft() - plus.getMarginRight();
int plusHeight = halfY - plus.getMarginTop() - plus.getMarginBottom();
layoutChild(plus, plusWidth, plusHeight);
setPositionChild( plus, halfX + plus.getMarginLeft(), plus.getMarginTop());
int minusWidth = halfX - minus.getMarginLeft() - minus.getMarginRight();
int minusHeight = halfY - minus.getMarginTop() - minus.getMarginBottom();
layoutChild(minus, minusWidth, minusHeight);
// Use plus.getMarginHeight() for better alignment.
setPositionChild( minus, halfX + plus.getMarginLeft(), halfY + minus.getMarginTop() );
//setVirtualExtent(layoutWidth, height);
setExtent(layoutWidth, height);
}
public EditField getNumberField() {
return number;
}
public void setNumberField(EditField number) {
this.number = number;
}
public ButtonField getPlusField() {
return plus;
}
public void setPlusField(ButtonField plus) {
this.plus = plus;
}
public Field getMinusField() {
return minus;
}
public void setMinusField(ButtonField minus) {
this.minus = minus;
}
}
The closest thing to what you are trying to achieve is
Few notes:
EditField always use USE_ALL_WIDTH. It doesn't matter if you requested it or not. Therefore, if you want to limit its width you have override its layout() method. In my code snippet, its width is limited by the maximum chars allowed for this field's value (see CustomEditField).
ButtonField ignores USE_ALL_WIDTH and USE_ALL_HEIGHT. Its extent depends only on the text within the button. In order to achieve the effect of USE_ALL_WIDTH, you have to add horizontal padding to it.
Unfortunately, the padding trick won't work if you want to achieve the USE_ALL_HEIGHT effect. When you add vertical padding to a button, at some stage it will repeat its background vertically. If it is required, you will have to write a custom button field for it.
Also check BlackBerry's advanced UI components at this page.
Here is the code:
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.FontMetrics;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.XYEdges;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.decor.Border;
import net.rim.device.api.ui.decor.BorderFactory;
import net.rim.device.api.ui.text.NumericTextFilter;
public class NumberClicker extends Manager {
private class CustomEditField extends EditField {
public int getPreferredWidth() {
FontMetrics fontMetrics = new FontMetrics();
getFont().getMetrics(fontMetrics);
return getMaxSize()*fontMetrics.getMaxCharWidth();
};
public int getPreferredHeight() {
// forcing the field to be single lined
return getFont().getHeight();
}
protected void layout(int width, int height) {
super.layout(
Math.min(width, getPreferredWidth()),
Math.min(height, getPreferredHeight())
);
}
}
final XYEdges MARGINS = new XYEdges(2,2,2,2);
EditField _number;
Manager _numberManager;
ButtonField _plus;
ButtonField _minus;
public NumberClicker() {
super(0);
Font font = getFont();
font = font.derive(Font.BOLD, font.getHeight() + 10);
_number = new CustomEditField();
_number.setFilter(new NumericTextFilter());
_number.setMaxSize(1);
_number.setFont(font);
setValue(1);
_numberManager = new Manager(0) {
protected void sublayout(int width, int height) {
layoutChild(_number, width, height);
setPositionChild(_number,
Math.max(0, (width - _number.getWidth())/2),
Math.max(0, (height - _number.getHeight())/2)
);
setExtent(width, height);
}
};
_numberManager.setBorder(BorderFactory.createRoundedBorder(new XYEdges()));
_numberManager.setMargin(MARGINS);
_numberManager.add(_number);
add(_numberManager);
_plus = new ButtonField("+", 0);
_plus.setMargin(MARGINS);
add(_plus);
_minus = new ButtonField("-");
_minus.setMargin(MARGINS);
add(_minus);
_plus.setRunnable(new Runnable() {
public void run() {
increment();
}
});
_minus.setRunnable(new Runnable() {
public void run() {
decrement();
}
});
}
private void increment() {
synchronized (UiApplication.getEventLock()) { //probably not needed here. overkill.
_number.setText(Integer.toString(Integer.parseInt(_number.getText().trim()) + 1));
}
}
private void decrement() {
if (Integer.parseInt(_number.getText()) <= 0) {
return;
}
synchronized (UiApplication.getEventLock()) { //probably not needed here. overkill.
_number.setText(Integer.toString(Integer.parseInt(_number.getText().trim()) - 1));
}
}
public void setValue(int value) {
if (value < 0) {
return;
}
synchronized (UiApplication.getEventLock()) { // MUST. can be called from non UI thread.
_number.setText(Integer.toString(value));
}
}
/**
* Compute sizes and positions of subfields.
*/
public void sublayout(int width, int height) {
int heightUsed = 0;
int halfX = width / 2;
Border border = _plus.getBorder();
int plusWidth = halfX - _plus.getMarginLeft() - _plus.getMarginRight();
int plusHeight = height - _plus.getMarginTop() - _plus.getMarginBottom();
// calculate horizontal padding so the button will look like USE_ALL_WIDTH
int plusHPadding = (Math.max(0, plusWidth - _plus.getPreferredWidth() - border.getLeft() - border.getRight()))/2;
_plus.setPadding(0, plusHPadding, 0, plusHPadding);
layoutChild(_plus, plusWidth, plusHeight);
setPositionChild( _plus, halfX + _plus.getMarginLeft(), _plus.getMarginTop());
heightUsed += _plus.getHeight() + _plus.getMarginTop() + _plus.getMarginBottom();
border = _minus.getBorder();
int minusWidth = halfX - _minus.getMarginLeft() - _minus.getMarginRight();
int minusHeight = height - _plus.getHeight() - _minus.getMarginTop() - _minus.getMarginBottom();
// calculate horizontal padding so the button will look like USE_ALL_WIDTH
int minusHPadding = (Math.max(0, minusWidth - _minus.getPreferredWidth() - border.getLeft() - border.getRight()))/2;
_minus.setPadding(0, minusHPadding, 0, minusHPadding);
layoutChild(_minus, minusWidth, minusHeight);
setPositionChild( _minus, halfX + _plus.getMarginLeft(), heightUsed + _minus.getMarginTop());
heightUsed += _minus.getHeight() + _minus.getMarginTop() + _minus.getMarginBottom();
int numberWidth = halfX - _numberManager.getMarginLeft() - _numberManager.getMarginRight();
int numberHeight = heightUsed - _numberManager.getMarginTop() - _numberManager.getMarginBottom();
layoutChild(_numberManager, numberWidth, numberHeight);
setPositionChild(_numberManager, _numberManager.getMarginLeft(), _numberManager.getMarginTop());
setExtent(width, heightUsed);
}
}

Java ME Calendar not displaying

I've been following this tutorial here: Link to tutorial. I can't seem to get the application displaying properly though. When I run the application I expect to see a screen like CalendarCanvas from tutorial, but I get this:
Here is my code, I'm using standard MIDP classes.
Class CreateCalendar:
import java.util.Date;
import java.util.Calendar;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
public class CreateCalendar
{
/**
* Array of strings which holds data for the month and day
* for the calendar application.
*/
static final String[] month_labels = new String[]
{
"January", "Febuary", "March", "April", "May", "June", "July", "August", "Sepetember", "October", "November", "Decemeber"
};
static final String[] weekdays_labels = new String[]
{
"Mon", "Tue", "Wed", "Thur", "Fri", "Sat", "Sun"
};
public int startWeekday = 0;
public int padding = 1;
public int borderWidth = 4;
public int borderColor = 0x009900;
/**
* Weekday Labels
*/
public Font weekdayFont = Font.getDefaultFont();
public int weekdayBackgroundColor = 0x009900;
public int weekdayColor = 0xffffff;
/**
* Month/Year Labels
*/
public Font headerFont = Font.getDefaultFont();
public int headerBackgroundColor = 0x009900;
public int headerColor = 0xffffff;
/**
* Cells Labels
*/
public Font font = Font.getDefaultFont();
public int foreColor = 0xffffff;
public int backgroundColor = 0x009900;
public int selectedBackgroundColor = 0xCCFF00;
public int selectedForegroundColor = 0xffffff;
/**
* Size properties
*/
int width = 0;
int height = 0;
int headerHeight = 0;
int weekHeight = 0;
int cellWidth = 0;
int cellHeight = 0;
/**
* Internal time properties
*/
long currentTimeStamp = 0;
Calendar calendar = null;
int weeks = 0;
public CreateCalendar(Date date)
{
calendar = Calendar.getInstance();
setDate(date);
initialize();
}
public Date getSelectedDate()
{
return calendar.getTime();
}
public void setDate(Date d)
{
currentTimeStamp = d.getTime();
calendar.setTime(d);
this.weeks = (int)Math.ceil(((double)getStartWeekday() + getMonthDays()) / 7);
}
public void setDate(long timestamp)
{
setDate(new Date(timestamp));
}
public void initialize()
{
this.cellWidth = font.stringWidth("MM") + 2 * padding;
this.cellHeight = font.getHeight() + 2 * padding;
this.headerHeight = headerFont.getHeight() + 2 * padding;
this.weekHeight = weekdayFont.getHeight() + 2 * padding;
this.width = 7 * (cellWidth + borderWidth) + borderWidth;
initHeight();
}
void initHeight()
{
this.height = headerHeight + weekHeight + this.weeks * (cellHeight + borderWidth) + borderWidth;
}
int getMonthDays()
{
int month = calendar.get(Calendar.MONTH);
switch (month)
{
case 3:
case 5:
case 8:
case 10:
return 30;
case 1:
int year = calendar.get(Calendar.YEAR);
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) ? 29 : 28;
default:
return 31;
}
}
int getStartWeekday()
{
Calendar c = Calendar.getInstance();
c.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
c.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
c.set(Calendar.DAY_OF_MONTH, 1);
return (c.get(Calendar.DAY_OF_WEEK) + 5) % 7;
}
public void KeyPressed(int key)
{
switch(key)
{
case Canvas.UP:
go(-7);
break;
case Canvas.DOWN:
go(7);
break;
case Canvas.RIGHT:
go(1);
break;
case Canvas.LEFT:
go(-1);
break;
}
}
void go(int delta)
{
int prevMonth = calendar.get(Calendar.MONTH);
setDate(currentTimeStamp + 864000000 * delta);
if(calendar.get(Calendar.MONTH) != prevMonth)
{
initHeight();
}
}
public void paint(Graphics g)
{
g.setColor(backgroundColor);
g.fillRect(0, 0, width, height);
g.setFont(headerFont);
g.setColor(headerColor);
g.drawString(month_labels[calendar.get(Calendar.MONTH)] + " " + calendar.get(Calendar.YEAR), width / 2, padding, Graphics.TOP | Graphics.HCENTER);
g.translate(0, headerHeight);
g.setColor(weekdayBackgroundColor);
g.fillRect(0, 0, width, weekHeight);
g.setColor(weekdayColor);
g.setFont(weekdayFont);
for(int i = 0; i < 7; i++)
{
g.drawString(weekdays_labels[(i + startWeekday) % 7], borderWidth + i * (cellWidth + borderWidth) + cellWidth / 2, padding, Graphics.TOP | Graphics.HCENTER);
}
g.translate(0, weekHeight);
g.setColor(borderColor);
for(int i = 0; i <= weeks; i++)
{
g.fillRect(0, i * (cellHeight + borderWidth), width, borderWidth);
}
for(int i = 0; i <=7; i++)
{
g.fillRect(i * (cellWidth + borderWidth), 0, borderWidth, height - headerHeight - weekHeight);
}
int days = getMonthDays();
int dayIndex = (getStartWeekday() - this.startWeekday + 7) % 7;
g.setColor(foreColor);
int currentDay = calendar.get(Calendar.DAY_OF_MONTH);
for(int i = 0; i < days; i++)
{
int weekday = (dayIndex + i) % 7;
int row = (dayIndex + i) / 7;
int x = borderWidth + weekday * (cellWidth + borderWidth) + cellWidth / 2;
int y = borderWidth + row * (cellHeight + cellWidth) + padding;
if(i + 1 == currentDay)
{
g.setColor(selectedBackgroundColor);
g.fillRect(borderWidth + weekday * (cellWidth + borderWidth), borderWidth + row * (cellHeight + borderWidth), cellWidth, cellHeight);
g.setColor(selectedForegroundColor);
}
g.drawString("" + (i + 1), x, y, Graphics.TOP | Graphics.HCENTER);
if(i + 1 == currentDay)
{
g.setColor(foreColor);
}
}
g.translate(0, - headerHeight - weekHeight);
}
private Date getTime() {
throw new UnsupportedOperationException("Not yet implemented"); //TODO get current Time
}
Class CalFrontEnd (extends MIDlet):
public class CalFrontEnd extends MIDlet
{
public CreateCalendar calendar;
protected Display display;
protected Form mainForm;
public CalFrontEnd()
{
}
public void startApp()
{
calendar = new CreateCalendar(new Date());
calendar.headerFont = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_LARGE);
calendar.weekdayFont = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_MEDIUM);
calendar.weekdayBackgroundColor = 0xccccff;
calendar.weekdayColor = 0x0000ff;
calendar.headerColor = 0xffffff;
calendar.initialize();
display.getDisplay(this).setCurrent(
new intCalendar(this));
}
public void pauseApp()
{
}
public void destroyApp(boolean destroy)
{
notifyDestroyed();
}
}}
Code in the class CreateCalendar looks very problematic.
In prior question you mentioned few minor variable name differences done to code from tutorial, but from what is shown in your code snippet, this is not so.
To find a way to reuse tutorial code, most straightforward approach would be like as follows.
Copy the source code from tutorial - files CalendarWidget.java and CalendarCanvas.java
Copy as-is, only adjust the package statements if necessary.
Modify CalFrontEnd about as follows
if needed, add import statement for CalendarCanvas
replace current code in startApp with simplest invocation for CalendarCanvas, like this:
public void startApp() {
Display.getDisplay(this).setCurrent(
new CalendarCanvas(this));
}
Test the code, tune and fix it until your MIDlet shows what you would expect of CalendarCanvas
After above is done, proceed with modifying the code to further match your needs.
Don't forget to test the changes you make, to make sure that things indeed work as you expect.

Resources