OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Compare Revisions

Regard whitespace Rev 20 → Rev 21

/trunk/OpenConcerto/lib/jsch-0.1.44.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/lib/jsch-0.1.44.jar
New file
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/trunk/OpenConcerto/lib/jOpenDocument-1.3b1.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/trunk/OpenConcerto/Configuration/main.properties
1,7 → 1,7
#OpenConcerto
#Thu Aug 25 18:19:03 CEST 2011
server.ip=192.168.1.10\:5432
systemRoot=OpenConcerto
systemRoot=ilmOC
base.root=Common
customer=Gestion_Default
server.driver=postgresql
/trunk/OpenConcerto/Configuration/Template/Default/Avoir.xml
120,7 → 120,7
<element location="K" type="fill" blankOnStyle="Normal">
<field base="Societe" table="AVOIR_CLIENT_ELEMENT" name="ID_TAXE" conditionField="PV_HT" conditionExpValue="0">
<field base="Societe" table="TAXE" name="TAUX"/>
<field base="Societe" table="TAXE" name="TAUX" op="/" number="100.0" />
</field>
</element>
 
/trunk/OpenConcerto/Configuration/Template/Default/Commande.xml
118,7 → 118,7
<element location="J" type="fill">
<field base="Societe" table="COMMANDE_ELEMENT" name="ID_TAXE">
<field base="Societe" table="TAXE" name="TAUX" suffix="%"/>
<field base="Societe" table="TAXE" name="TAUX" op="/" number="100.0"/>
</field>
</element>
/trunk/OpenConcerto/Configuration/Template/Default/VenteFacture.xml
95,8 → 95,8
<element location="B63" type="fill">
<field base="Societe" table="SAISIE_VENTE_FACTURE" name="ID_MODE_REGLEMENT">
 
<field base="Societe" table="MODE_REGLEMENT" name="NOM" prefix="Réglement par " conditionField="COMPTANT" conditionExpValue="false" display="false"/>
<field base="Societe" table="MODE_REGLEMENT" name="NOM" prefix="Régler par " conditionField="COMPTANT" conditionExpValue="true" display="false"/>
<field base="Societe" table="MODE_REGLEMENT" name="NOM" prefix="Règlement souhaité" conditionField="COMPTANT" conditionExpValue="false" display="false"/>
<field base="Societe" table="MODE_REGLEMENT" name="NOM" prefix="Facture acquitée par" conditionField="COMPTANT" conditionExpValue="true" display="false"/>
 
<field base="Societe" table="MODE_REGLEMENT" name="ID_TYPE_REGLEMENT">
<field base="Societe" table="TYPE_REGLEMENT" name="NOM" valuesExpected="Indéfini"/>
147,7 → 147,7
<element location="K" type="fill">
<field base="Societe" table="SAISIE_VENTE_FACTURE_ELEMENT" name="ID_TAXE" conditionField="PV_HT" conditionExpValue="0">
<field base="Societe" table="TAXE" name="TAUX"/>
<field base="Societe" table="TAXE" name="TAUX" op="/" number="100.0"/>
</field>
</element>
 
/trunk/OpenConcerto/Configuration/Template/Default/Devis.xml
110,7 → 110,7
 
<element location="K" type="fill">
<field base="Societe" table="DEVIS_ELEMENT" name="ID_TAXE" conditionField="PV_HT" conditionExpValue="0">
<field base="Societe" table="TAXE" name="TAUX" suffix="%" />
<field base="Societe" table="TAXE" name="TAUX" op="/" number="100.0" />
</field>
</element>
/trunk/OpenConcerto/Configuration/Template/Default/CommandeClient.xml
119,7 → 119,7
<element location="J" type="fill">
<field base="Societe" table="COMMANDE_CLIENT_ELEMENT" name="ID_TAXE">
<field base="Societe" table="TAXE" name="TAUX" suffix="%"/>
<field base="Societe" table="TAXE" name="TAUX" op="/" number="100.0"/>
</field>
</element>
/trunk/OpenConcerto/src/com/jcraft/jzlib/Inflate.java
New file
0,0 → 1,374
/* -*-mode:java; c-basic-offset:2; -*- */
/*
Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
 
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program is based on zlib-1.1.3, so all credit should go authors
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
* and contributors of zlib.
*/
 
package com.jcraft.jzlib;
 
final class Inflate{
static final private int MAX_WBITS=15; // 32K LZ77 window
 
// preset dictionary flag in zlib header
static final private int PRESET_DICT=0x20;
 
static final int Z_NO_FLUSH=0;
static final int Z_PARTIAL_FLUSH=1;
static final int Z_SYNC_FLUSH=2;
static final int Z_FULL_FLUSH=3;
static final int Z_FINISH=4;
 
static final private int Z_DEFLATED=8;
 
static final private int Z_OK=0;
static final private int Z_STREAM_END=1;
static final private int Z_NEED_DICT=2;
static final private int Z_ERRNO=-1;
static final private int Z_STREAM_ERROR=-2;
static final private int Z_DATA_ERROR=-3;
static final private int Z_MEM_ERROR=-4;
static final private int Z_BUF_ERROR=-5;
static final private int Z_VERSION_ERROR=-6;
 
static final private int METHOD=0; // waiting for method byte
static final private int FLAG=1; // waiting for flag byte
static final private int DICT4=2; // four dictionary check bytes to go
static final private int DICT3=3; // three dictionary check bytes to go
static final private int DICT2=4; // two dictionary check bytes to go
static final private int DICT1=5; // one dictionary check byte to go
static final private int DICT0=6; // waiting for inflateSetDictionary
static final private int BLOCKS=7; // decompressing blocks
static final private int CHECK4=8; // four check bytes to go
static final private int CHECK3=9; // three check bytes to go
static final private int CHECK2=10; // two check bytes to go
static final private int CHECK1=11; // one check byte to go
static final private int DONE=12; // finished check, done
static final private int BAD=13; // got an error--stay here
 
int mode; // current inflate mode
 
// mode dependent information
int method; // if FLAGS, method byte
 
// if CHECK, check values to compare
long[] was=new long[1] ; // computed check value
long need; // stream check value
 
// if BAD, inflateSync's marker bytes count
int marker;
 
// mode independent information
int nowrap; // flag for no wrapper
int wbits; // log2(window size) (8..15, defaults to 15)
 
InfBlocks blocks; // current inflate_blocks state
 
int inflateReset(ZStream z){
if(z == null || z.istate == null) return Z_STREAM_ERROR;
z.total_in = z.total_out = 0;
z.msg = null;
z.istate.mode = z.istate.nowrap!=0 ? BLOCKS : METHOD;
z.istate.blocks.reset(z, null);
return Z_OK;
}
 
int inflateEnd(ZStream z){
if(blocks != null)
blocks.free(z);
blocks=null;
// ZFREE(z, z->state);
return Z_OK;
}
 
int inflateInit(ZStream z, int w){
z.msg = null;
blocks = null;
 
// handle undocumented nowrap option (no zlib header or check)
nowrap = 0;
if(w < 0){
w = - w;
nowrap = 1;
}
 
// set window size
if(w<8 ||w>15){
inflateEnd(z);
return Z_STREAM_ERROR;
}
wbits=w;
 
z.istate.blocks=new InfBlocks(z,
z.istate.nowrap!=0 ? null : this,
1<<w);
 
// reset state
inflateReset(z);
return Z_OK;
}
 
int inflate(ZStream z, int f){
int r;
int b;
 
if(z == null || z.istate == null || z.next_in == null)
return Z_STREAM_ERROR;
f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
r = Z_BUF_ERROR;
while (true){
//System.out.println("mode: "+z.istate.mode);
switch (z.istate.mode){
case METHOD:
 
if(z.avail_in==0)return r;r=f;
 
z.avail_in--; z.total_in++;
if(((z.istate.method = z.next_in[z.next_in_index++])&0xf)!=Z_DEFLATED){
z.istate.mode = BAD;
z.msg="unknown compression method";
z.istate.marker = 5; // can't try inflateSync
break;
}
if((z.istate.method>>4)+8>z.istate.wbits){
z.istate.mode = BAD;
z.msg="invalid window size";
z.istate.marker = 5; // can't try inflateSync
break;
}
z.istate.mode=FLAG;
case FLAG:
 
if(z.avail_in==0)return r;r=f;
 
z.avail_in--; z.total_in++;
b = (z.next_in[z.next_in_index++])&0xff;
 
if((((z.istate.method << 8)+b) % 31)!=0){
z.istate.mode = BAD;
z.msg = "incorrect header check";
z.istate.marker = 5; // can't try inflateSync
break;
}
 
if((b&PRESET_DICT)==0){
z.istate.mode = BLOCKS;
break;
}
z.istate.mode = DICT4;
case DICT4:
 
if(z.avail_in==0)return r;r=f;
 
z.avail_in--; z.total_in++;
z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
z.istate.mode=DICT3;
case DICT3:
 
if(z.avail_in==0)return r;r=f;
 
z.avail_in--; z.total_in++;
z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
z.istate.mode=DICT2;
case DICT2:
 
if(z.avail_in==0)return r;r=f;
 
z.avail_in--; z.total_in++;
z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
z.istate.mode=DICT1;
case DICT1:
 
if(z.avail_in==0)return r;r=f;
 
z.avail_in--; z.total_in++;
z.istate.need += (z.next_in[z.next_in_index++]&0xffL);
z.adler = z.istate.need;
z.istate.mode = DICT0;
return Z_NEED_DICT;
case DICT0:
z.istate.mode = BAD;
z.msg = "need dictionary";
z.istate.marker = 0; // can try inflateSync
return Z_STREAM_ERROR;
case BLOCKS:
 
r = z.istate.blocks.proc(z, r);
if(r == Z_DATA_ERROR){
z.istate.mode = BAD;
z.istate.marker = 0; // can try inflateSync
break;
}
if(r == Z_OK){
r = f;
}
if(r != Z_STREAM_END){
return r;
}
r = f;
z.istate.blocks.reset(z, z.istate.was);
if(z.istate.nowrap!=0){
z.istate.mode=DONE;
break;
}
z.istate.mode=CHECK4;
case CHECK4:
 
if(z.avail_in==0)return r;r=f;
 
z.avail_in--; z.total_in++;
z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
z.istate.mode=CHECK3;
case CHECK3:
 
if(z.avail_in==0)return r;r=f;
 
z.avail_in--; z.total_in++;
z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
z.istate.mode = CHECK2;
case CHECK2:
 
if(z.avail_in==0)return r;r=f;
 
z.avail_in--; z.total_in++;
z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
z.istate.mode = CHECK1;
case CHECK1:
 
if(z.avail_in==0)return r;r=f;
 
z.avail_in--; z.total_in++;
z.istate.need+=(z.next_in[z.next_in_index++]&0xffL);
 
if(((int)(z.istate.was[0])) != ((int)(z.istate.need))){
z.istate.mode = BAD;
z.msg = "incorrect data check";
z.istate.marker = 5; // can't try inflateSync
break;
}
 
z.istate.mode = DONE;
case DONE:
return Z_STREAM_END;
case BAD:
return Z_DATA_ERROR;
default:
return Z_STREAM_ERROR;
}
}
}
 
 
int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength){
int index=0;
int length = dictLength;
if(z==null || z.istate == null|| z.istate.mode != DICT0)
return Z_STREAM_ERROR;
 
if(z._adler.adler32(1L, dictionary, 0, dictLength)!=z.adler){
return Z_DATA_ERROR;
}
 
z.adler = z._adler.adler32(0, null, 0, 0);
 
if(length >= (1<<z.istate.wbits)){
length = (1<<z.istate.wbits)-1;
index=dictLength - length;
}
z.istate.blocks.set_dictionary(dictionary, index, length);
z.istate.mode = BLOCKS;
return Z_OK;
}
 
static private byte[] mark = {(byte)0, (byte)0, (byte)0xff, (byte)0xff};
 
int inflateSync(ZStream z){
int n; // number of bytes to look at
int p; // pointer to bytes
int m; // number of marker bytes found in a row
long r, w; // temporaries to save total_in and total_out
 
// set up
if(z == null || z.istate == null)
return Z_STREAM_ERROR;
if(z.istate.mode != BAD){
z.istate.mode = BAD;
z.istate.marker = 0;
}
if((n=z.avail_in)==0)
return Z_BUF_ERROR;
p=z.next_in_index;
m=z.istate.marker;
 
// search
while (n!=0 && m < 4){
if(z.next_in[p] == mark[m]){
m++;
}
else if(z.next_in[p]!=0){
m = 0;
}
else{
m = 4 - m;
}
p++; n--;
}
 
// restore
z.total_in += p-z.next_in_index;
z.next_in_index = p;
z.avail_in = n;
z.istate.marker = m;
 
// return no joy or set up to restart on a new block
if(m != 4){
return Z_DATA_ERROR;
}
r=z.total_in; w=z.total_out;
inflateReset(z);
z.total_in=r; z.total_out = w;
z.istate.mode = BLOCKS;
return Z_OK;
}
 
// Returns true if inflate is currently at the end of a block generated
// by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
// implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
// but removes the length bytes of the resulting empty stored block. When
// decompressing, PPP checks that at the end of input packet, inflate is
// waiting for these length bytes.
int inflateSyncPoint(ZStream z){
if(z == null || z.istate == null || z.istate.blocks == null)
return Z_STREAM_ERROR;
return z.istate.blocks.sync_point();
}
}
/trunk/OpenConcerto/src/com/jcraft/jzlib/Deflate.java
New file
0,0 → 1,1623
/* -*-mode:java; c-basic-offset:2; -*- */
/*
Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
 
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program is based on zlib-1.1.3, so all credit should go authors
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
* and contributors of zlib.
*/
 
package com.jcraft.jzlib;
 
public
final class Deflate{
 
static final private int MAX_MEM_LEVEL=9;
 
static final private int Z_DEFAULT_COMPRESSION=-1;
 
static final private int MAX_WBITS=15; // 32K LZ77 window
static final private int DEF_MEM_LEVEL=8;
 
static class Config{
int good_length; // reduce lazy search above this match length
int max_lazy; // do not perform lazy search above this match length
int nice_length; // quit search above this match length
int max_chain;
int func;
Config(int good_length, int max_lazy,
int nice_length, int max_chain, int func){
this.good_length=good_length;
this.max_lazy=max_lazy;
this.nice_length=nice_length;
this.max_chain=max_chain;
this.func=func;
}
}
static final private int STORED=0;
static final private int FAST=1;
static final private int SLOW=2;
static final private Config[] config_table;
static{
config_table=new Config[10];
// good lazy nice chain
config_table[0]=new Config(0, 0, 0, 0, STORED);
config_table[1]=new Config(4, 4, 8, 4, FAST);
config_table[2]=new Config(4, 5, 16, 8, FAST);
config_table[3]=new Config(4, 6, 32, 32, FAST);
 
config_table[4]=new Config(4, 4, 16, 16, SLOW);
config_table[5]=new Config(8, 16, 32, 32, SLOW);
config_table[6]=new Config(8, 16, 128, 128, SLOW);
config_table[7]=new Config(8, 32, 128, 256, SLOW);
config_table[8]=new Config(32, 128, 258, 1024, SLOW);
config_table[9]=new Config(32, 258, 258, 4096, SLOW);
}
 
static final private String[] z_errmsg = {
"need dictionary", // Z_NEED_DICT 2
"stream end", // Z_STREAM_END 1
"", // Z_OK 0
"file error", // Z_ERRNO (-1)
"stream error", // Z_STREAM_ERROR (-2)
"data error", // Z_DATA_ERROR (-3)
"insufficient memory", // Z_MEM_ERROR (-4)
"buffer error", // Z_BUF_ERROR (-5)
"incompatible version",// Z_VERSION_ERROR (-6)
""
};
 
// block not completed, need more input or more output
static final private int NeedMore=0;
 
// block flush performed
static final private int BlockDone=1;
 
// finish started, need only more output at next deflate
static final private int FinishStarted=2;
 
// finish done, accept no more input or output
static final private int FinishDone=3;
 
// preset dictionary flag in zlib header
static final private int PRESET_DICT=0x20;
 
static final private int Z_FILTERED=1;
static final private int Z_HUFFMAN_ONLY=2;
static final private int Z_DEFAULT_STRATEGY=0;
 
static final private int Z_NO_FLUSH=0;
static final private int Z_PARTIAL_FLUSH=1;
static final private int Z_SYNC_FLUSH=2;
static final private int Z_FULL_FLUSH=3;
static final private int Z_FINISH=4;
 
static final private int Z_OK=0;
static final private int Z_STREAM_END=1;
static final private int Z_NEED_DICT=2;
static final private int Z_ERRNO=-1;
static final private int Z_STREAM_ERROR=-2;
static final private int Z_DATA_ERROR=-3;
static final private int Z_MEM_ERROR=-4;
static final private int Z_BUF_ERROR=-5;
static final private int Z_VERSION_ERROR=-6;
 
static final private int INIT_STATE=42;
static final private int BUSY_STATE=113;
static final private int FINISH_STATE=666;
 
// The deflate compression method
static final private int Z_DEFLATED=8;
 
static final private int STORED_BLOCK=0;
static final private int STATIC_TREES=1;
static final private int DYN_TREES=2;
 
// The three kinds of block type
static final private int Z_BINARY=0;
static final private int Z_ASCII=1;
static final private int Z_UNKNOWN=2;
 
static final private int Buf_size=8*2;
 
// repeat previous bit length 3-6 times (2 bits of repeat count)
static final private int REP_3_6=16;
 
// repeat a zero length 3-10 times (3 bits of repeat count)
static final private int REPZ_3_10=17;
 
// repeat a zero length 11-138 times (7 bits of repeat count)
static final private int REPZ_11_138=18;
 
static final private int MIN_MATCH=3;
static final private int MAX_MATCH=258;
static final private int MIN_LOOKAHEAD=(MAX_MATCH+MIN_MATCH+1);
 
static final private int MAX_BITS=15;
static final private int D_CODES=30;
static final private int BL_CODES=19;
static final private int LENGTH_CODES=29;
static final private int LITERALS=256;
static final private int L_CODES=(LITERALS+1+LENGTH_CODES);
static final private int HEAP_SIZE=(2*L_CODES+1);
 
static final private int END_BLOCK=256;
 
ZStream strm; // pointer back to this zlib stream
int status; // as the name implies
byte[] pending_buf; // output still pending
int pending_buf_size; // size of pending_buf
int pending_out; // next pending byte to output to the stream
int pending; // nb of bytes in the pending buffer
int noheader; // suppress zlib header and adler32
byte data_type; // UNKNOWN, BINARY or ASCII
byte method; // STORED (for zip only) or DEFLATED
int last_flush; // value of flush param for previous deflate call
 
int w_size; // LZ77 window size (32K by default)
int w_bits; // log2(w_size) (8..16)
int w_mask; // w_size - 1
 
byte[] window;
// Sliding window. Input bytes are read into the second half of the window,
// and move to the first half later to keep a dictionary of at least wSize
// bytes. With this organization, matches are limited to a distance of
// wSize-MAX_MATCH bytes, but this ensures that IO is always
// performed with a length multiple of the block size. Also, it limits
// the window size to 64K, which is quite useful on MSDOS.
// To do: use the user input buffer as sliding window.
 
int window_size;
// Actual size of window: 2*wSize, except when the user input buffer
// is directly used as sliding window.
 
short[] prev;
// Link to older string with same hash index. To limit the size of this
// array to 64K, this link is maintained only for the last 32K strings.
// An index in this array is thus a window index modulo 32K.
 
short[] head; // Heads of the hash chains or NIL.
 
int ins_h; // hash index of string to be inserted
int hash_size; // number of elements in hash table
int hash_bits; // log2(hash_size)
int hash_mask; // hash_size-1
 
// Number of bits by which ins_h must be shifted at each input
// step. It must be such that after MIN_MATCH steps, the oldest
// byte no longer takes part in the hash key, that is:
// hash_shift * MIN_MATCH >= hash_bits
int hash_shift;
 
// Window position at the beginning of the current output block. Gets
// negative when the window is moved backwards.
 
int block_start;
 
int match_length; // length of best match
int prev_match; // previous match
int match_available; // set if previous match exists
int strstart; // start of string to insert
int match_start; // start of matching string
int lookahead; // number of valid bytes ahead in window
 
// Length of the best match at previous step. Matches not greater than this
// are discarded. This is used in the lazy match evaluation.
int prev_length;
 
// To speed up deflation, hash chains are never searched beyond this
// length. A higher limit improves compression ratio but degrades the speed.
int max_chain_length;
 
// Attempt to find a better match only when the current match is strictly
// smaller than this value. This mechanism is used only for compression
// levels >= 4.
int max_lazy_match;
 
// Insert new strings in the hash table only if the match length is not
// greater than this length. This saves time but degrades compression.
// max_insert_length is used only for compression levels <= 3.
 
int level; // compression level (1..9)
int strategy; // favor or force Huffman coding
 
// Use a faster search when the previous match is longer than this
int good_match;
 
// Stop searching when current match exceeds this
int nice_match;
 
short[] dyn_ltree; // literal and length tree
short[] dyn_dtree; // distance tree
short[] bl_tree; // Huffman tree for bit lengths
 
Tree l_desc=new Tree(); // desc for literal tree
Tree d_desc=new Tree(); // desc for distance tree
Tree bl_desc=new Tree(); // desc for bit length tree
 
// number of codes at each bit length for an optimal tree
short[] bl_count=new short[MAX_BITS+1];
 
// heap used to build the Huffman trees
int[] heap=new int[2*L_CODES+1];
 
int heap_len; // number of elements in the heap
int heap_max; // element of largest frequency
// The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
// The same heap array is used to build all trees.
 
// Depth of each subtree used as tie breaker for trees of equal frequency
byte[] depth=new byte[2*L_CODES+1];
 
int l_buf; // index for literals or lengths */
 
// Size of match buffer for literals/lengths. There are 4 reasons for
// limiting lit_bufsize to 64K:
// - frequencies can be kept in 16 bit counters
// - if compression is not successful for the first block, all input
// data is still in the window so we can still emit a stored block even
// when input comes from standard input. (This can also be done for
// all blocks if lit_bufsize is not greater than 32K.)
// - if compression is not successful for a file smaller than 64K, we can
// even emit a stored file instead of a stored block (saving 5 bytes).
// This is applicable only for zip (not gzip or zlib).
// - creating new Huffman trees less frequently may not provide fast
// adaptation to changes in the input data statistics. (Take for
// example a binary file with poorly compressible code followed by
// a highly compressible string table.) Smaller buffer sizes give
// fast adaptation but have of course the overhead of transmitting
// trees more frequently.
// - I can't count above 4
int lit_bufsize;
 
int last_lit; // running index in l_buf
 
// Buffer for distances. To simplify the code, d_buf and l_buf have
// the same number of elements. To use different lengths, an extra flag
// array would be necessary.
 
int d_buf; // index of pendig_buf
 
int opt_len; // bit length of current block with optimal trees
int static_len; // bit length of current block with static trees
int matches; // number of string matches in current block
int last_eob_len; // bit length of EOB code for last block
 
// Output buffer. bits are inserted starting at the bottom (least
// significant bits).
short bi_buf;
 
// Number of valid bits in bi_buf. All bits above the last valid bit
// are always zero.
int bi_valid;
 
Deflate(){
dyn_ltree=new short[HEAP_SIZE*2];
dyn_dtree=new short[(2*D_CODES+1)*2]; // distance tree
bl_tree=new short[(2*BL_CODES+1)*2]; // Huffman tree for bit lengths
}
 
void lm_init() {
window_size=2*w_size;
 
head[hash_size-1]=0;
for(int i=0; i<hash_size-1; i++){
head[i]=0;
}
 
// Set the default configuration parameters:
max_lazy_match = Deflate.config_table[level].max_lazy;
good_match = Deflate.config_table[level].good_length;
nice_match = Deflate.config_table[level].nice_length;
max_chain_length = Deflate.config_table[level].max_chain;
 
strstart = 0;
block_start = 0;
lookahead = 0;
match_length = prev_length = MIN_MATCH-1;
match_available = 0;
ins_h = 0;
}
 
// Initialize the tree data structures for a new zlib stream.
void tr_init(){
 
l_desc.dyn_tree = dyn_ltree;
l_desc.stat_desc = StaticTree.static_l_desc;
 
d_desc.dyn_tree = dyn_dtree;
d_desc.stat_desc = StaticTree.static_d_desc;
 
bl_desc.dyn_tree = bl_tree;
bl_desc.stat_desc = StaticTree.static_bl_desc;
 
bi_buf = 0;
bi_valid = 0;
last_eob_len = 8; // enough lookahead for inflate
 
// Initialize the first block of the first file:
init_block();
}
 
void init_block(){
// Initialize the trees.
for(int i = 0; i < L_CODES; i++) dyn_ltree[i*2] = 0;
for(int i= 0; i < D_CODES; i++) dyn_dtree[i*2] = 0;
for(int i= 0; i < BL_CODES; i++) bl_tree[i*2] = 0;
 
dyn_ltree[END_BLOCK*2] = 1;
opt_len = static_len = 0;
last_lit = matches = 0;
}
 
// Restore the heap property by moving down the tree starting at node k,
// exchanging a node with the smallest of its two sons if necessary, stopping
// when the heap property is re-established (each father smaller than its
// two sons).
void pqdownheap(short[] tree, // the tree to restore
int k // node to move down
){
int v = heap[k];
int j = k << 1; // left son of k
while (j <= heap_len) {
// Set j to the smallest of the two sons:
if (j < heap_len &&
smaller(tree, heap[j+1], heap[j], depth)){
j++;
}
// Exit if v is smaller than both sons
if(smaller(tree, v, heap[j], depth)) break;
 
// Exchange v with the smallest son
heap[k]=heap[j]; k = j;
// And continue down the tree, setting j to the left son of k
j <<= 1;
}
heap[k] = v;
}
 
static boolean smaller(short[] tree, int n, int m, byte[] depth){
short tn2=tree[n*2];
short tm2=tree[m*2];
return (tn2<tm2 ||
(tn2==tm2 && depth[n] <= depth[m]));
}
 
// Scan a literal or distance tree to determine the frequencies of the codes
// in the bit length tree.
void scan_tree (short[] tree,// the tree to be scanned
int max_code // and its largest code of non zero frequency
){
int n; // iterates over all tree elements
int prevlen = -1; // last emitted length
int curlen; // length of current code
int nextlen = tree[0*2+1]; // length of next code
int count = 0; // repeat count of the current code
int max_count = 7; // max repeat count
int min_count = 4; // min repeat count
 
if (nextlen == 0){ max_count = 138; min_count = 3; }
tree[(max_code+1)*2+1] = (short)0xffff; // guard
 
for(n = 0; n <= max_code; n++) {
curlen = nextlen; nextlen = tree[(n+1)*2+1];
if(++count < max_count && curlen == nextlen) {
continue;
}
else if(count < min_count) {
bl_tree[curlen*2] += count;
}
else if(curlen != 0) {
if(curlen != prevlen) bl_tree[curlen*2]++;
bl_tree[REP_3_6*2]++;
}
else if(count <= 10) {
bl_tree[REPZ_3_10*2]++;
}
else{
bl_tree[REPZ_11_138*2]++;
}
count = 0; prevlen = curlen;
if(nextlen == 0) {
max_count = 138; min_count = 3;
}
else if(curlen == nextlen) {
max_count = 6; min_count = 3;
}
else{
max_count = 7; min_count = 4;
}
}
}
 
// Construct the Huffman tree for the bit lengths and return the index in
// bl_order of the last bit length code to send.
int build_bl_tree(){
int max_blindex; // index of last bit length code of non zero freq
 
// Determine the bit length frequencies for literal and distance trees
scan_tree(dyn_ltree, l_desc.max_code);
scan_tree(dyn_dtree, d_desc.max_code);
 
// Build the bit length tree:
bl_desc.build_tree(this);
// opt_len now includes the length of the tree representations, except
// the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
 
// Determine the number of bit length codes to send. The pkzip format
// requires that at least 4 bit length codes be sent. (appnote.txt says
// 3 but the actual value used is 4.)
for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
if (bl_tree[Tree.bl_order[max_blindex]*2+1] != 0) break;
}
// Update opt_len to include the bit length tree and counts
opt_len += 3*(max_blindex+1) + 5+5+4;
 
return max_blindex;
}
 
 
// Send the header for a block using dynamic Huffman trees: the counts, the
// lengths of the bit length codes, the literal tree and the distance tree.
// IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
void send_all_trees(int lcodes, int dcodes, int blcodes){
int rank; // index in bl_order
 
send_bits(lcodes-257, 5); // not +255 as stated in appnote.txt
send_bits(dcodes-1, 5);
send_bits(blcodes-4, 4); // not -3 as stated in appnote.txt
for (rank = 0; rank < blcodes; rank++) {
send_bits(bl_tree[Tree.bl_order[rank]*2+1], 3);
}
send_tree(dyn_ltree, lcodes-1); // literal tree
send_tree(dyn_dtree, dcodes-1); // distance tree
}
 
// Send a literal or distance tree in compressed form, using the codes in
// bl_tree.
void send_tree (short[] tree,// the tree to be sent
int max_code // and its largest code of non zero frequency
){
int n; // iterates over all tree elements
int prevlen = -1; // last emitted length
int curlen; // length of current code
int nextlen = tree[0*2+1]; // length of next code
int count = 0; // repeat count of the current code
int max_count = 7; // max repeat count
int min_count = 4; // min repeat count
 
if (nextlen == 0){ max_count = 138; min_count = 3; }
 
for (n = 0; n <= max_code; n++) {
curlen = nextlen; nextlen = tree[(n+1)*2+1];
if(++count < max_count && curlen == nextlen) {
continue;
}
else if(count < min_count) {
do { send_code(curlen, bl_tree); } while (--count != 0);
}
else if(curlen != 0){
if(curlen != prevlen){
send_code(curlen, bl_tree); count--;
}
send_code(REP_3_6, bl_tree);
send_bits(count-3, 2);
}
else if(count <= 10){
send_code(REPZ_3_10, bl_tree);
send_bits(count-3, 3);
}
else{
send_code(REPZ_11_138, bl_tree);
send_bits(count-11, 7);
}
count = 0; prevlen = curlen;
if(nextlen == 0){
max_count = 138; min_count = 3;
}
else if(curlen == nextlen){
max_count = 6; min_count = 3;
}
else{
max_count = 7; min_count = 4;
}
}
}
 
// Output a byte on the stream.
// IN assertion: there is enough room in pending_buf.
final void put_byte(byte[] p, int start, int len){
System.arraycopy(p, start, pending_buf, pending, len);
pending+=len;
}
 
final void put_byte(byte c){
pending_buf[pending++]=c;
}
final void put_short(int w) {
put_byte((byte)(w/*&0xff*/));
put_byte((byte)(w>>>8));
}
final void putShortMSB(int b){
put_byte((byte)(b>>8));
put_byte((byte)(b/*&0xff*/));
}
 
final void send_code(int c, short[] tree){
int c2=c*2;
send_bits((tree[c2]&0xffff), (tree[c2+1]&0xffff));
}
 
void send_bits(int value, int length){
int len = length;
if (bi_valid > (int)Buf_size - len) {
int val = value;
// bi_buf |= (val << bi_valid);
bi_buf |= ((val << bi_valid)&0xffff);
put_short(bi_buf);
bi_buf = (short)(val >>> (Buf_size - bi_valid));
bi_valid += len - Buf_size;
} else {
// bi_buf |= (value) << bi_valid;
bi_buf |= (((value) << bi_valid)&0xffff);
bi_valid += len;
}
}
 
// Send one empty static block to give enough lookahead for inflate.
// This takes 10 bits, of which 7 may remain in the bit buffer.
// The current inflate code requires 9 bits of lookahead. If the
// last two codes for the previous block (real code plus EOB) were coded
// on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
// the last real code. In this case we send two empty static blocks instead
// of one. (There are no problems if the previous block is stored or fixed.)
// To simplify the code, we assume the worst case of last real code encoded
// on one bit only.
void _tr_align(){
send_bits(STATIC_TREES<<1, 3);
send_code(END_BLOCK, StaticTree.static_ltree);
 
bi_flush();
 
// Of the 10 bits for the empty block, we have already sent
// (10 - bi_valid) bits. The lookahead for the last real code (before
// the EOB of the previous block) was thus at least one plus the length
// of the EOB plus what we have just sent of the empty static block.
if (1 + last_eob_len + 10 - bi_valid < 9) {
send_bits(STATIC_TREES<<1, 3);
send_code(END_BLOCK, StaticTree.static_ltree);
bi_flush();
}
last_eob_len = 7;
}
 
 
// Save the match info and tally the frequency counts. Return true if
// the current block must be flushed.
boolean _tr_tally (int dist, // distance of matched string
int lc // match length-MIN_MATCH or unmatched char (if dist==0)
){
 
pending_buf[d_buf+last_lit*2] = (byte)(dist>>>8);
pending_buf[d_buf+last_lit*2+1] = (byte)dist;
 
pending_buf[l_buf+last_lit] = (byte)lc; last_lit++;
 
if (dist == 0) {
// lc is the unmatched char
dyn_ltree[lc*2]++;
}
else {
matches++;
// Here, lc is the match length - MIN_MATCH
dist--; // dist = match distance - 1
dyn_ltree[(Tree._length_code[lc]+LITERALS+1)*2]++;
dyn_dtree[Tree.d_code(dist)*2]++;
}
 
if ((last_lit & 0x1fff) == 0 && level > 2) {
// Compute an upper bound for the compressed length
int out_length = last_lit*8;
int in_length = strstart - block_start;
int dcode;
for (dcode = 0; dcode < D_CODES; dcode++) {
out_length += (int)dyn_dtree[dcode*2] *
(5L+Tree.extra_dbits[dcode]);
}
out_length >>>= 3;
if ((matches < (last_lit/2)) && out_length < in_length/2) return true;
}
 
return (last_lit == lit_bufsize-1);
// We avoid equality with lit_bufsize because of wraparound at 64K
// on 16 bit machines and because stored blocks are restricted to
// 64K-1 bytes.
}
 
// Send the block data compressed using the given Huffman trees
void compress_block(short[] ltree, short[] dtree){
int dist; // distance of matched string
int lc; // match length or unmatched char (if dist == 0)
int lx = 0; // running index in l_buf
int code; // the code to send
int extra; // number of extra bits to send
 
if (last_lit != 0){
do{
dist=((pending_buf[d_buf+lx*2]<<8)&0xff00)|
(pending_buf[d_buf+lx*2+1]&0xff);
lc=(pending_buf[l_buf+lx])&0xff; lx++;
 
if(dist == 0){
send_code(lc, ltree); // send a literal byte
}
else{
// Here, lc is the match length - MIN_MATCH
code = Tree._length_code[lc];
 
send_code(code+LITERALS+1, ltree); // send the length code
extra = Tree.extra_lbits[code];
if(extra != 0){
lc -= Tree.base_length[code];
send_bits(lc, extra); // send the extra length bits
}
dist--; // dist is now the match distance - 1
code = Tree.d_code(dist);
 
send_code(code, dtree); // send the distance code
extra = Tree.extra_dbits[code];
if (extra != 0) {
dist -= Tree.base_dist[code];
send_bits(dist, extra); // send the extra distance bits
}
} // literal or match pair ?
 
// Check that the overlay between pending_buf and d_buf+l_buf is ok:
}
while (lx < last_lit);
}
 
send_code(END_BLOCK, ltree);
last_eob_len = ltree[END_BLOCK*2+1];
}
 
// Set the data type to ASCII or BINARY, using a crude approximation:
// binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
// IN assertion: the fields freq of dyn_ltree are set and the total of all
// frequencies does not exceed 64K (to fit in an int on 16 bit machines).
void set_data_type(){
int n = 0;
int ascii_freq = 0;
int bin_freq = 0;
while(n<7){ bin_freq += dyn_ltree[n*2]; n++;}
while(n<128){ ascii_freq += dyn_ltree[n*2]; n++;}
while(n<LITERALS){ bin_freq += dyn_ltree[n*2]; n++;}
data_type=(byte)(bin_freq > (ascii_freq >>> 2) ? Z_BINARY : Z_ASCII);
}
 
// Flush the bit buffer, keeping at most 7 bits in it.
void bi_flush(){
if (bi_valid == 16) {
put_short(bi_buf);
bi_buf=0;
bi_valid=0;
}
else if (bi_valid >= 8) {
put_byte((byte)bi_buf);
bi_buf>>>=8;
bi_valid-=8;
}
}
 
// Flush the bit buffer and align the output on a byte boundary
void bi_windup(){
if (bi_valid > 8) {
put_short(bi_buf);
} else if (bi_valid > 0) {
put_byte((byte)bi_buf);
}
bi_buf = 0;
bi_valid = 0;
}
 
// Copy a stored block, storing first the length and its
// one's complement if requested.
void copy_block(int buf, // the input data
int len, // its length
boolean header // true if block header must be written
){
int index=0;
bi_windup(); // align on byte boundary
last_eob_len = 8; // enough lookahead for inflate
 
if (header) {
put_short((short)len);
put_short((short)~len);
}
 
// while(len--!=0) {
// put_byte(window[buf+index]);
// index++;
// }
put_byte(window, buf, len);
}
 
void flush_block_only(boolean eof){
_tr_flush_block(block_start>=0 ? block_start : -1,
strstart-block_start,
eof);
block_start=strstart;
strm.flush_pending();
}
 
// Copy without compression as much as possible from the input stream, return
// the current block state.
// This function does not insert new strings in the dictionary since
// uncompressible data is probably not useful. This function is used
// only for the level=0 compression option.
// NOTE: this function should be optimized to avoid extra copying from
// window to pending_buf.
int deflate_stored(int flush){
// Stored blocks are limited to 0xffff bytes, pending_buf is limited
// to pending_buf_size, and each stored block has a 5 byte header:
 
int max_block_size = 0xffff;
int max_start;
 
if(max_block_size > pending_buf_size - 5) {
max_block_size = pending_buf_size - 5;
}
 
// Copy as much as possible from input to output:
while(true){
// Fill the window as much as possible:
if(lookahead<=1){
fill_window();
if(lookahead==0 && flush==Z_NO_FLUSH) return NeedMore;
if(lookahead==0) break; // flush the current block
}
 
strstart+=lookahead;
lookahead=0;
 
// Emit a stored block if pending_buf will be full:
max_start=block_start+max_block_size;
if(strstart==0|| strstart>=max_start) {
// strstart == 0 is possible when wraparound on 16-bit machine
lookahead = (int)(strstart-max_start);
strstart = (int)max_start;
flush_block_only(false);
if(strm.avail_out==0) return NeedMore;
 
}
 
// Flush if we may have to slide, otherwise block_start may become
// negative and the data will be gone:
if(strstart-block_start >= w_size-MIN_LOOKAHEAD) {
flush_block_only(false);
if(strm.avail_out==0) return NeedMore;
}
}
 
flush_block_only(flush == Z_FINISH);
if(strm.avail_out==0)
return (flush == Z_FINISH) ? FinishStarted : NeedMore;
 
return flush == Z_FINISH ? FinishDone : BlockDone;
}
 
// Send a stored block
void _tr_stored_block(int buf, // input block
int stored_len, // length of input block
boolean eof // true if this is the last block for a file
){
send_bits((STORED_BLOCK<<1)+(eof?1:0), 3); // send block type
copy_block(buf, stored_len, true); // with header
}
 
// Determine the best encoding for the current block: dynamic trees, static
// trees or store, and output the encoded block to the zip file.
void _tr_flush_block(int buf, // input block, or NULL if too old
int stored_len, // length of input block
boolean eof // true if this is the last block for a file
) {
int opt_lenb, static_lenb;// opt_len and static_len in bytes
int max_blindex = 0; // index of last bit length code of non zero freq
 
// Build the Huffman trees unless a stored block is forced
if(level > 0) {
// Check if the file is ascii or binary
if(data_type == Z_UNKNOWN) set_data_type();
 
// Construct the literal and distance trees
l_desc.build_tree(this);
 
d_desc.build_tree(this);
 
// At this point, opt_len and static_len are the total bit lengths of
// the compressed block data, excluding the tree representations.
 
// Build the bit length tree for the above two trees, and get the index
// in bl_order of the last bit length code to send.
max_blindex=build_bl_tree();
 
// Determine the best encoding. Compute first the block length in bytes
opt_lenb=(opt_len+3+7)>>>3;
static_lenb=(static_len+3+7)>>>3;
 
if(static_lenb<=opt_lenb) opt_lenb=static_lenb;
}
else {
opt_lenb=static_lenb=stored_len+5; // force a stored block
}
 
if(stored_len+4<=opt_lenb && buf != -1){
// 4: two words for the lengths
// The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
// Otherwise we can't have processed more than WSIZE input bytes since
// the last block flush, because compression would have been
// successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
// transform a block into a stored block.
_tr_stored_block(buf, stored_len, eof);
}
else if(static_lenb == opt_lenb){
send_bits((STATIC_TREES<<1)+(eof?1:0), 3);
compress_block(StaticTree.static_ltree, StaticTree.static_dtree);
}
else{
send_bits((DYN_TREES<<1)+(eof?1:0), 3);
send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
compress_block(dyn_ltree, dyn_dtree);
}
 
// The above check is made mod 2^32, for files larger than 512 MB
// and uLong implemented on 32 bits.
 
init_block();
 
if(eof){
bi_windup();
}
}
 
// Fill the window when the lookahead becomes insufficient.
// Updates strstart and lookahead.
//
// IN assertion: lookahead < MIN_LOOKAHEAD
// OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
// At least one byte has been read, or avail_in == 0; reads are
// performed for at least two bytes (required for the zip translate_eol
// option -- not supported here).
void fill_window(){
int n, m;
int p;
int more; // Amount of free space at the end of the window.
 
do{
more = (window_size-lookahead-strstart);
 
// Deal with !@#$% 64K limit:
if(more==0 && strstart==0 && lookahead==0){
more = w_size;
}
else if(more==-1) {
// Very unlikely, but possible on 16 bit machine if strstart == 0
// and lookahead == 1 (input done one byte at time)
more--;
 
// If the window is almost full and there is insufficient lookahead,
// move the upper half to the lower one to make room in the upper half.
}
else if(strstart >= w_size+ w_size-MIN_LOOKAHEAD) {
System.arraycopy(window, w_size, window, 0, w_size);
match_start-=w_size;
strstart-=w_size; // we now have strstart >= MAX_DIST
block_start-=w_size;
 
// Slide the hash table (could be avoided with 32 bit values
// at the expense of memory usage). We slide even when level == 0
// to keep the hash table consistent if we switch back to level > 0
// later. (Using level 0 permanently is not an optimal usage of
// zlib, so we don't care about this pathological case.)
 
n = hash_size;
p=n;
do {
m = (head[--p]&0xffff);
head[p]=(m>=w_size ? (short)(m-w_size) : 0);
}
while (--n != 0);
 
n = w_size;
p = n;
do {
m = (prev[--p]&0xffff);
prev[p] = (m >= w_size ? (short)(m-w_size) : 0);
// If n is not on any hash chain, prev[n] is garbage but
// its value will never be used.
}
while (--n!=0);
more += w_size;
}
 
if (strm.avail_in == 0) return;
 
// If there was no sliding:
// strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
// more == window_size - lookahead - strstart
// => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
// => more >= window_size - 2*WSIZE + 2
// In the BIG_MEM or MMAP case (not yet supported),
// window_size == input_size + MIN_LOOKAHEAD &&
// strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
// Otherwise, window_size == 2*WSIZE so more >= 2.
// If there was sliding, more >= WSIZE. So in all cases, more >= 2.
 
n = strm.read_buf(window, strstart + lookahead, more);
lookahead += n;
 
// Initialize the hash value now that we have some input:
if(lookahead >= MIN_MATCH) {
ins_h = window[strstart]&0xff;
ins_h=(((ins_h)<<hash_shift)^(window[strstart+1]&0xff))&hash_mask;
}
// If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
// but this is not important since only literal bytes will be emitted.
}
while (lookahead < MIN_LOOKAHEAD && strm.avail_in != 0);
}
 
// Compress as much as possible from the input stream, return the current
// block state.
// This function does not perform lazy evaluation of matches and inserts
// new strings in the dictionary only for unmatched strings or for short
// matches. It is used only for the fast compression options.
int deflate_fast(int flush){
// short hash_head = 0; // head of the hash chain
int hash_head = 0; // head of the hash chain
boolean bflush; // set if current block must be flushed
 
while(true){
// Make sure that we always have enough lookahead, except
// at the end of the input file. We need MAX_MATCH bytes
// for the next match, plus MIN_MATCH bytes to insert the
// string following the next match.
if(lookahead < MIN_LOOKAHEAD){
fill_window();
if(lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH){
return NeedMore;
}
if(lookahead == 0) break; // flush the current block
}
 
// Insert the string window[strstart .. strstart+2] in the
// dictionary, and set hash_head to the head of the hash chain:
if(lookahead >= MIN_MATCH){
ins_h=(((ins_h)<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff))&hash_mask;
 
// prev[strstart&w_mask]=hash_head=head[ins_h];
hash_head=(head[ins_h]&0xffff);
prev[strstart&w_mask]=head[ins_h];
head[ins_h]=(short)strstart;
}
 
// Find the longest match, discarding those <= prev_length.
// At this point we have always match_length < MIN_MATCH
 
if(hash_head!=0L &&
((strstart-hash_head)&0xffff) <= w_size-MIN_LOOKAHEAD
){
// To simplify the code, we prevent matches with the string
// of window index 0 (in particular we have to avoid a match
// of the string with itself at the start of the input file).
if(strategy != Z_HUFFMAN_ONLY){
match_length=longest_match (hash_head);
}
// longest_match() sets match_start
}
if(match_length>=MIN_MATCH){
// check_match(strstart, match_start, match_length);
 
bflush=_tr_tally(strstart-match_start, match_length-MIN_MATCH);
 
lookahead -= match_length;
 
// Insert new strings in the hash table only if the match length
// is not too large. This saves time but degrades compression.
if(match_length <= max_lazy_match &&
lookahead >= MIN_MATCH) {
match_length--; // string at strstart already in hash table
do{
strstart++;
 
ins_h=((ins_h<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff))&hash_mask;
// prev[strstart&w_mask]=hash_head=head[ins_h];
hash_head=(head[ins_h]&0xffff);
prev[strstart&w_mask]=head[ins_h];
head[ins_h]=(short)strstart;
 
// strstart never exceeds WSIZE-MAX_MATCH, so there are
// always MIN_MATCH bytes ahead.
}
while (--match_length != 0);
strstart++;
}
else{
strstart += match_length;
match_length = 0;
ins_h = window[strstart]&0xff;
 
ins_h=(((ins_h)<<hash_shift)^(window[strstart+1]&0xff))&hash_mask;
// If lookahead < MIN_MATCH, ins_h is garbage, but it does not
// matter since it will be recomputed at next deflate call.
}
}
else {
// No match, output a literal byte
 
bflush=_tr_tally(0, window[strstart]&0xff);
lookahead--;
strstart++;
}
if (bflush){
 
flush_block_only(false);
if(strm.avail_out==0) return NeedMore;
}
}
 
flush_block_only(flush == Z_FINISH);
if(strm.avail_out==0){
if(flush == Z_FINISH) return FinishStarted;
else return NeedMore;
}
return flush==Z_FINISH ? FinishDone : BlockDone;
}
 
// Same as above, but achieves better compression. We use a lazy
// evaluation for matches: a match is finally adopted only if there is
// no better match at the next window position.
int deflate_slow(int flush){
// short hash_head = 0; // head of hash chain
int hash_head = 0; // head of hash chain
boolean bflush; // set if current block must be flushed
 
// Process the input block.
while(true){
// Make sure that we always have enough lookahead, except
// at the end of the input file. We need MAX_MATCH bytes
// for the next match, plus MIN_MATCH bytes to insert the
// string following the next match.
 
if (lookahead < MIN_LOOKAHEAD) {
fill_window();
if(lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
return NeedMore;
}
if(lookahead == 0) break; // flush the current block
}
 
// Insert the string window[strstart .. strstart+2] in the
// dictionary, and set hash_head to the head of the hash chain:
 
if(lookahead >= MIN_MATCH) {
ins_h=(((ins_h)<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff)) & hash_mask;
// prev[strstart&w_mask]=hash_head=head[ins_h];
hash_head=(head[ins_h]&0xffff);
prev[strstart&w_mask]=head[ins_h];
head[ins_h]=(short)strstart;
}
 
// Find the longest match, discarding those <= prev_length.
prev_length = match_length; prev_match = match_start;
match_length = MIN_MATCH-1;
 
if (hash_head != 0 && prev_length < max_lazy_match &&
((strstart-hash_head)&0xffff) <= w_size-MIN_LOOKAHEAD
){
// To simplify the code, we prevent matches with the string
// of window index 0 (in particular we have to avoid a match
// of the string with itself at the start of the input file).
 
if(strategy != Z_HUFFMAN_ONLY) {
match_length = longest_match(hash_head);
}
// longest_match() sets match_start
 
if (match_length <= 5 && (strategy == Z_FILTERED ||
(match_length == MIN_MATCH &&
strstart - match_start > 4096))) {
 
// If prev_match is also MIN_MATCH, match_start is garbage
// but we will ignore the current match anyway.
match_length = MIN_MATCH-1;
}
}
 
// If there was a match at the previous step and the current
// match is not better, output the previous match:
if(prev_length >= MIN_MATCH && match_length <= prev_length) {
int max_insert = strstart + lookahead - MIN_MATCH;
// Do not insert strings in hash table beyond this.
 
// check_match(strstart-1, prev_match, prev_length);
 
bflush=_tr_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
 
// Insert in hash table all strings up to the end of the match.
// strstart-1 and strstart are already inserted. If there is not
// enough lookahead, the last two strings are not inserted in
// the hash table.
lookahead -= prev_length-1;
prev_length -= 2;
do{
if(++strstart <= max_insert) {
ins_h=(((ins_h)<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff))&hash_mask;
//prev[strstart&w_mask]=hash_head=head[ins_h];
hash_head=(head[ins_h]&0xffff);
prev[strstart&w_mask]=head[ins_h];
head[ins_h]=(short)strstart;
}
}
while(--prev_length != 0);
match_available = 0;
match_length = MIN_MATCH-1;
strstart++;
 
if (bflush){
flush_block_only(false);
if(strm.avail_out==0) return NeedMore;
}
} else if (match_available!=0) {
 
// If there was no match at the previous position, output a
// single literal. If there was a match but the current match
// is longer, truncate the previous match to a single literal.
 
bflush=_tr_tally(0, window[strstart-1]&0xff);
 
if (bflush) {
flush_block_only(false);
}
strstart++;
lookahead--;
if(strm.avail_out == 0) return NeedMore;
} else {
// There is no previous match to compare with, wait for
// the next step to decide.
 
match_available = 1;
strstart++;
lookahead--;
}
}
 
if(match_available!=0) {
bflush=_tr_tally(0, window[strstart-1]&0xff);
match_available = 0;
}
flush_block_only(flush == Z_FINISH);
 
if(strm.avail_out==0){
if(flush == Z_FINISH) return FinishStarted;
else return NeedMore;
}
 
return flush == Z_FINISH ? FinishDone : BlockDone;
}
 
int longest_match(int cur_match){
int chain_length = max_chain_length; // max hash chain length
int scan = strstart; // current string
int match; // matched string
int len; // length of current match
int best_len = prev_length; // best match length so far
int limit = strstart>(w_size-MIN_LOOKAHEAD) ?
strstart-(w_size-MIN_LOOKAHEAD) : 0;
int nice_match=this.nice_match;
 
// Stop when cur_match becomes <= limit. To simplify the code,
// we prevent matches with the string of window index 0.
 
int wmask = w_mask;
 
int strend = strstart + MAX_MATCH;
byte scan_end1 = window[scan+best_len-1];
byte scan_end = window[scan+best_len];
 
// The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
// It is easy to get rid of this optimization if necessary.
 
// Do not waste too much time if we already have a good match:
if (prev_length >= good_match) {
chain_length >>= 2;
}
 
// Do not look for matches beyond the end of the input. This is necessary
// to make deflate deterministic.
if (nice_match > lookahead) nice_match = lookahead;
 
do {
match = cur_match;
 
// Skip to next match if the match length cannot increase
// or if the match length is less than 2:
if (window[match+best_len] != scan_end ||
window[match+best_len-1] != scan_end1 ||
window[match] != window[scan] ||
window[++match] != window[scan+1]) continue;
 
// The check at best_len-1 can be removed because it will be made
// again later. (This heuristic is not always a win.)
// It is not necessary to compare scan[2] and match[2] since they
// are always equal when the other bytes match, given that
// the hash keys are equal and that HASH_BITS >= 8.
scan += 2; match++;
 
// We check for insufficient lookahead only every 8th comparison;
// the 256th check will be made at strstart+258.
do {
} while (window[++scan] == window[++match] &&
window[++scan] == window[++match] &&
window[++scan] == window[++match] &&
window[++scan] == window[++match] &&
window[++scan] == window[++match] &&
window[++scan] == window[++match] &&
window[++scan] == window[++match] &&
window[++scan] == window[++match] &&
scan < strend);
 
len = MAX_MATCH - (int)(strend - scan);
scan = strend - MAX_MATCH;
 
if(len>best_len) {
match_start = cur_match;
best_len = len;
if (len >= nice_match) break;
scan_end1 = window[scan+best_len-1];
scan_end = window[scan+best_len];
}
 
} while ((cur_match = (prev[cur_match & wmask]&0xffff)) > limit
&& --chain_length != 0);
 
if (best_len <= lookahead) return best_len;
return lookahead;
}
int deflateInit(ZStream strm, int level, int bits){
return deflateInit2(strm, level, Z_DEFLATED, bits, DEF_MEM_LEVEL,
Z_DEFAULT_STRATEGY);
}
int deflateInit(ZStream strm, int level){
return deflateInit(strm, level, MAX_WBITS);
}
int deflateInit2(ZStream strm, int level, int method, int windowBits,
int memLevel, int strategy){
int noheader = 0;
// byte[] my_version=ZLIB_VERSION;
 
//
// if (version == null || version[0] != my_version[0]
// || stream_size != sizeof(z_stream)) {
// return Z_VERSION_ERROR;
// }
 
strm.msg = null;
 
if (level == Z_DEFAULT_COMPRESSION) level = 6;
 
if (windowBits < 0) { // undocumented feature: suppress zlib header
noheader = 1;
windowBits = -windowBits;
}
 
if (memLevel < 1 || memLevel > MAX_MEM_LEVEL ||
method != Z_DEFLATED ||
windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
return Z_STREAM_ERROR;
}
 
strm.dstate = (Deflate)this;
 
this.noheader = noheader;
w_bits = windowBits;
w_size = 1 << w_bits;
w_mask = w_size - 1;
 
hash_bits = memLevel + 7;
hash_size = 1 << hash_bits;
hash_mask = hash_size - 1;
hash_shift = ((hash_bits+MIN_MATCH-1)/MIN_MATCH);
 
window = new byte[w_size*2];
prev = new short[w_size];
head = new short[hash_size];
 
lit_bufsize = 1 << (memLevel + 6); // 16K elements by default
 
// We overlay pending_buf and d_buf+l_buf. This works since the average
// output size for (length,distance) codes is <= 24 bits.
pending_buf = new byte[lit_bufsize*4];
pending_buf_size = lit_bufsize*4;
 
d_buf = lit_bufsize/2;
l_buf = (1+2)*lit_bufsize;
 
this.level = level;
 
//System.out.println("level="+level);
 
this.strategy = strategy;
this.method = (byte)method;
 
return deflateReset(strm);
}
 
int deflateReset(ZStream strm){
strm.total_in = strm.total_out = 0;
strm.msg = null; //
strm.data_type = Z_UNKNOWN;
 
pending = 0;
pending_out = 0;
 
if(noheader < 0) {
noheader = 0; // was set to -1 by deflate(..., Z_FINISH);
}
status = (noheader!=0) ? BUSY_STATE : INIT_STATE;
strm.adler=strm._adler.adler32(0, null, 0, 0);
 
last_flush = Z_NO_FLUSH;
 
tr_init();
lm_init();
return Z_OK;
}
 
int deflateEnd(){
if(status!=INIT_STATE && status!=BUSY_STATE && status!=FINISH_STATE){
return Z_STREAM_ERROR;
}
// Deallocate in reverse order of allocations:
pending_buf=null;
head=null;
prev=null;
window=null;
// free
// dstate=null;
return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
}
 
int deflateParams(ZStream strm, int _level, int _strategy){
int err=Z_OK;
 
if(_level == Z_DEFAULT_COMPRESSION){
_level = 6;
}
if(_level < 0 || _level > 9 ||
_strategy < 0 || _strategy > Z_HUFFMAN_ONLY) {
return Z_STREAM_ERROR;
}
 
if(config_table[level].func!=config_table[_level].func &&
strm.total_in != 0) {
// Flush the last buffer:
err = strm.deflate(Z_PARTIAL_FLUSH);
}
 
if(level != _level) {
level = _level;
max_lazy_match = config_table[level].max_lazy;
good_match = config_table[level].good_length;
nice_match = config_table[level].nice_length;
max_chain_length = config_table[level].max_chain;
}
strategy = _strategy;
return err;
}
 
int deflateSetDictionary (ZStream strm, byte[] dictionary, int dictLength){
int length = dictLength;
int index=0;
 
if(dictionary == null || status != INIT_STATE)
return Z_STREAM_ERROR;
 
strm.adler=strm._adler.adler32(strm.adler, dictionary, 0, dictLength);
 
if(length < MIN_MATCH) return Z_OK;
if(length > w_size-MIN_LOOKAHEAD){
length = w_size-MIN_LOOKAHEAD;
index=dictLength-length; // use the tail of the dictionary
}
System.arraycopy(dictionary, index, window, 0, length);
strstart = length;
block_start = length;
 
// Insert all strings in the hash table (except for the last two bytes).
// s->lookahead stays null, so s->ins_h will be recomputed at the next
// call of fill_window.
 
ins_h = window[0]&0xff;
ins_h=(((ins_h)<<hash_shift)^(window[1]&0xff))&hash_mask;
 
for(int n=0; n<=length-MIN_MATCH; n++){
ins_h=(((ins_h)<<hash_shift)^(window[(n)+(MIN_MATCH-1)]&0xff))&hash_mask;
prev[n&w_mask]=head[ins_h];
head[ins_h]=(short)n;
}
return Z_OK;
}
 
int deflate(ZStream strm, int flush){
int old_flush;
 
if(flush>Z_FINISH || flush<0){
return Z_STREAM_ERROR;
}
 
if(strm.next_out == null ||
(strm.next_in == null && strm.avail_in != 0) ||
(status == FINISH_STATE && flush != Z_FINISH)) {
strm.msg=z_errmsg[Z_NEED_DICT-(Z_STREAM_ERROR)];
return Z_STREAM_ERROR;
}
if(strm.avail_out == 0){
strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
return Z_BUF_ERROR;
}
 
this.strm = strm; // just in case
old_flush = last_flush;
last_flush = flush;
 
// Write the zlib header
if(status == INIT_STATE) {
int header = (Z_DEFLATED+((w_bits-8)<<4))<<8;
int level_flags=((level-1)&0xff)>>1;
 
if(level_flags>3) level_flags=3;
header |= (level_flags<<6);
if(strstart!=0) header |= PRESET_DICT;
header+=31-(header % 31);
 
status=BUSY_STATE;
putShortMSB(header);
 
 
// Save the adler32 of the preset dictionary:
if(strstart!=0){
putShortMSB((int)(strm.adler>>>16));
putShortMSB((int)(strm.adler&0xffff));
}
strm.adler=strm._adler.adler32(0, null, 0, 0);
}
 
// Flush as much pending output as possible
if(pending != 0) {
strm.flush_pending();
if(strm.avail_out == 0) {
//System.out.println(" avail_out==0");
// Since avail_out is 0, deflate will be called again with
// more output space, but possibly with both pending and
// avail_in equal to zero. There won't be anything to do,
// but this is not an error situation so make sure we
// return OK instead of BUF_ERROR at next call of deflate:
last_flush = -1;
return Z_OK;
}
 
// Make sure there is something to do and avoid duplicate consecutive
// flushes. For repeated and useless calls with Z_FINISH, we keep
// returning Z_STREAM_END instead of Z_BUFF_ERROR.
}
else if(strm.avail_in==0 && flush <= old_flush &&
flush != Z_FINISH) {
strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
return Z_BUF_ERROR;
}
 
// User must not provide more input after the first FINISH:
if(status == FINISH_STATE && strm.avail_in != 0) {
strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
return Z_BUF_ERROR;
}
 
// Start a new block or continue the current one.
if(strm.avail_in!=0 || lookahead!=0 ||
(flush != Z_NO_FLUSH && status != FINISH_STATE)) {
int bstate=-1;
switch(config_table[level].func){
case STORED:
bstate = deflate_stored(flush);
break;
case FAST:
bstate = deflate_fast(flush);
break;
case SLOW:
bstate = deflate_slow(flush);
break;
default:
}
 
if (bstate==FinishStarted || bstate==FinishDone) {
status = FINISH_STATE;
}
if (bstate==NeedMore || bstate==FinishStarted) {
if(strm.avail_out == 0) {
last_flush = -1; // avoid BUF_ERROR next call, see above
}
return Z_OK;
// If flush != Z_NO_FLUSH && avail_out == 0, the next call
// of deflate should use the same flush parameter to make sure
// that the flush is complete. So we don't have to output an
// empty block here, this will be done at next call. This also
// ensures that for a very small output buffer, we emit at most
// one empty block.
}
 
if (bstate==BlockDone) {
if(flush == Z_PARTIAL_FLUSH) {
_tr_align();
}
else { // FULL_FLUSH or SYNC_FLUSH
_tr_stored_block(0, 0, false);
// For a full flush, this empty block will be recognized
// as a special marker by inflate_sync().
if(flush == Z_FULL_FLUSH) {
//state.head[s.hash_size-1]=0;
for(int i=0; i<hash_size/*-1*/; i++) // forget history
head[i]=0;
}
}
strm.flush_pending();
if(strm.avail_out == 0) {
last_flush = -1; // avoid BUF_ERROR at next call, see above
return Z_OK;
}
}
}
 
if(flush!=Z_FINISH) return Z_OK;
if(noheader!=0) return Z_STREAM_END;
 
// Write the zlib trailer (adler32)
putShortMSB((int)(strm.adler>>>16));
putShortMSB((int)(strm.adler&0xffff));
strm.flush_pending();
 
// If avail_out is zero, the application will call deflate again
// to flush the rest.
noheader = -1; // write the trailer only once!
return pending != 0 ? Z_OK : Z_STREAM_END;
}
}
/trunk/OpenConcerto/src/com/jcraft/jzlib/ZStreamException.java
New file
0,0 → 1,44
/* -*-mode:java; c-basic-offset:2; -*- */
/*
Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
 
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program is based on zlib-1.1.3, so all credit should go authors
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
* and contributors of zlib.
*/
 
package com.jcraft.jzlib;
 
public class ZStreamException extends java.io.IOException {
public ZStreamException() {
super();
}
public ZStreamException(String s) {
super(s);
}
}
/trunk/OpenConcerto/src/com/jcraft/jzlib/ZInputStream.java
New file
0,0 → 1,149
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2001 Lapo Luchini.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
 
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program is based on zlib-1.1.3, so all credit should go authors
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
* and contributors of zlib.
*/
 
package com.jcraft.jzlib;
import java.io.*;
 
public class ZInputStream extends FilterInputStream {
 
protected ZStream z=new ZStream();
protected int bufsize=512;
protected int flush=JZlib.Z_NO_FLUSH;
protected byte[] buf=new byte[bufsize],
buf1=new byte[1];
protected boolean compress;
 
protected InputStream in=null;
 
public ZInputStream(InputStream in) {
this(in, false);
}
public ZInputStream(InputStream in, boolean nowrap) {
super(in);
this.in=in;
z.inflateInit(nowrap);
compress=false;
z.next_in=buf;
z.next_in_index=0;
z.avail_in=0;
}
 
public ZInputStream(InputStream in, int level) {
super(in);
this.in=in;
z.deflateInit(level);
compress=true;
z.next_in=buf;
z.next_in_index=0;
z.avail_in=0;
}
 
/*public int available() throws IOException {
return inf.finished() ? 0 : 1;
}*/
 
public int read() throws IOException {
if(read(buf1, 0, 1)==-1)
return(-1);
return(buf1[0]&0xFF);
}
 
private boolean nomoreinput=false;
 
public int read(byte[] b, int off, int len) throws IOException {
if(len==0)
return(0);
int err;
z.next_out=b;
z.next_out_index=off;
z.avail_out=len;
do {
if((z.avail_in==0)&&(!nomoreinput)) { // if buffer is empty and more input is avaiable, refill it
z.next_in_index=0;
z.avail_in=in.read(buf, 0, bufsize);//(bufsize<z.avail_out ? bufsize : z.avail_out));
if(z.avail_in==-1) {
z.avail_in=0;
nomoreinput=true;
}
}
if(compress)
err=z.deflate(flush);
else
err=z.inflate(flush);
if(nomoreinput&&(err==JZlib.Z_BUF_ERROR))
return(-1);
if(err!=JZlib.Z_OK && err!=JZlib.Z_STREAM_END)
throw new ZStreamException((compress ? "de" : "in")+"flating: "+z.msg);
if((nomoreinput||err==JZlib.Z_STREAM_END)&&(z.avail_out==len))
return(-1);
}
while(z.avail_out==len&&err==JZlib.Z_OK);
//System.err.print("("+(len-z.avail_out)+")");
return(len-z.avail_out);
}
 
public long skip(long n) throws IOException {
int len=512;
if(n<len)
len=(int)n;
byte[] tmp=new byte[len];
return((long)read(tmp));
}
 
public int getFlushMode() {
return(flush);
}
 
public void setFlushMode(int flush) {
this.flush=flush;
}
 
/**
* Returns the total number of bytes input so far.
*/
public long getTotalIn() {
return z.total_in;
}
 
/**
* Returns the total number of bytes output so far.
*/
public long getTotalOut() {
return z.total_out;
}
 
public void close() throws IOException{
in.close();
}
}
/trunk/OpenConcerto/src/com/jcraft/jzlib/ZStream.java
New file
0,0 → 1,211
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
 
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program is based on zlib-1.1.3, so all credit should go authors
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
* and contributors of zlib.
*/
 
package com.jcraft.jzlib;
 
final public class ZStream{
 
static final private int MAX_WBITS=15; // 32K LZ77 window
static final private int DEF_WBITS=MAX_WBITS;
 
static final private int Z_NO_FLUSH=0;
static final private int Z_PARTIAL_FLUSH=1;
static final private int Z_SYNC_FLUSH=2;
static final private int Z_FULL_FLUSH=3;
static final private int Z_FINISH=4;
 
static final private int MAX_MEM_LEVEL=9;
 
static final private int Z_OK=0;
static final private int Z_STREAM_END=1;
static final private int Z_NEED_DICT=2;
static final private int Z_ERRNO=-1;
static final private int Z_STREAM_ERROR=-2;
static final private int Z_DATA_ERROR=-3;
static final private int Z_MEM_ERROR=-4;
static final private int Z_BUF_ERROR=-5;
static final private int Z_VERSION_ERROR=-6;
 
public byte[] next_in; // next input byte
public int next_in_index;
public int avail_in; // number of bytes available at next_in
public long total_in; // total nb of input bytes read so far
 
public byte[] next_out; // next output byte should be put there
public int next_out_index;
public int avail_out; // remaining free space at next_out
public long total_out; // total nb of bytes output so far
 
public String msg;
 
Deflate dstate;
Inflate istate;
 
int data_type; // best guess about the data type: ascii or binary
 
public long adler;
Adler32 _adler=new Adler32();
 
public int inflateInit(){
return inflateInit(DEF_WBITS);
}
public int inflateInit(boolean nowrap){
return inflateInit(DEF_WBITS, nowrap);
}
public int inflateInit(int w){
return inflateInit(w, false);
}
 
public int inflateInit(int w, boolean nowrap){
istate=new Inflate();
return istate.inflateInit(this, nowrap?-w:w);
}
 
public int inflate(int f){
if(istate==null) return Z_STREAM_ERROR;
return istate.inflate(this, f);
}
public int inflateEnd(){
if(istate==null) return Z_STREAM_ERROR;
int ret=istate.inflateEnd(this);
istate = null;
return ret;
}
public int inflateSync(){
if(istate == null)
return Z_STREAM_ERROR;
return istate.inflateSync(this);
}
public int inflateSetDictionary(byte[] dictionary, int dictLength){
if(istate == null)
return Z_STREAM_ERROR;
return istate.inflateSetDictionary(this, dictionary, dictLength);
}
 
public int deflateInit(int level){
return deflateInit(level, MAX_WBITS);
}
public int deflateInit(int level, boolean nowrap){
return deflateInit(level, MAX_WBITS, nowrap);
}
public int deflateInit(int level, int bits){
return deflateInit(level, bits, false);
}
public int deflateInit(int level, int bits, boolean nowrap){
dstate=new Deflate();
return dstate.deflateInit(this, level, nowrap?-bits:bits);
}
public int deflate(int flush){
if(dstate==null){
return Z_STREAM_ERROR;
}
return dstate.deflate(this, flush);
}
public int deflateEnd(){
if(dstate==null) return Z_STREAM_ERROR;
int ret=dstate.deflateEnd();
dstate=null;
return ret;
}
public int deflateParams(int level, int strategy){
if(dstate==null) return Z_STREAM_ERROR;
return dstate.deflateParams(this, level, strategy);
}
public int deflateSetDictionary (byte[] dictionary, int dictLength){
if(dstate == null)
return Z_STREAM_ERROR;
return dstate.deflateSetDictionary(this, dictionary, dictLength);
}
 
// Flush as much pending output as possible. All deflate() output goes
// through this function so some applications may wish to modify it
// to avoid allocating a large strm->next_out buffer and copying into it.
// (See also read_buf()).
void flush_pending(){
int len=dstate.pending;
 
if(len>avail_out) len=avail_out;
if(len==0) return;
 
if(dstate.pending_buf.length<=dstate.pending_out ||
next_out.length<=next_out_index ||
dstate.pending_buf.length<(dstate.pending_out+len) ||
next_out.length<(next_out_index+len)){
System.out.println(dstate.pending_buf.length+", "+dstate.pending_out+
", "+next_out.length+", "+next_out_index+", "+len);
System.out.println("avail_out="+avail_out);
}
 
System.arraycopy(dstate.pending_buf, dstate.pending_out,
next_out, next_out_index, len);
 
next_out_index+=len;
dstate.pending_out+=len;
total_out+=len;
avail_out-=len;
dstate.pending-=len;
if(dstate.pending==0){
dstate.pending_out=0;
}
}
 
// Read a new buffer from the current input stream, update the adler32
// and total number of bytes read. All deflate() input goes through
// this function so some applications may wish to modify it to avoid
// allocating a large strm->next_in buffer and copying from it.
// (See also flush_pending()).
int read_buf(byte[] buf, int start, int size) {
int len=avail_in;
 
if(len>size) len=size;
if(len==0) return 0;
 
avail_in-=len;
 
if(dstate.noheader==0) {
adler=_adler.adler32(adler, next_in, next_in_index, len);
}
System.arraycopy(next_in, next_in_index, buf, start, len);
next_in_index += len;
total_in += len;
return len;
}
 
public void free(){
next_in=null;
next_out=null;
msg=null;
_adler=null;
}
}
/trunk/OpenConcerto/src/com/jcraft/jzlib/ZOutputStream.java
New file
0,0 → 1,156
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2001 Lapo Luchini.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
 
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program is based on zlib-1.1.3, so all credit should go authors
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
* and contributors of zlib.
*/
 
package com.jcraft.jzlib;
import java.io.*;
 
public class ZOutputStream extends OutputStream {
 
protected ZStream z=new ZStream();
protected int bufsize=512;
protected int flush=JZlib.Z_NO_FLUSH;
protected byte[] buf=new byte[bufsize],
buf1=new byte[1];
protected boolean compress;
 
protected OutputStream out;
 
public ZOutputStream(OutputStream out) {
super();
this.out=out;
z.inflateInit();
compress=false;
}
 
public ZOutputStream(OutputStream out, int level) {
this(out, level, false);
}
public ZOutputStream(OutputStream out, int level, boolean nowrap) {
super();
this.out=out;
z.deflateInit(level, nowrap);
compress=true;
}
 
public void write(int b) throws IOException {
buf1[0]=(byte)b;
write(buf1, 0, 1);
}
 
public void write(byte b[], int off, int len) throws IOException {
if(len==0)
return;
int err;
z.next_in=b;
z.next_in_index=off;
z.avail_in=len;
do{
z.next_out=buf;
z.next_out_index=0;
z.avail_out=bufsize;
if(compress)
err=z.deflate(flush);
else
err=z.inflate(flush);
if(err!=JZlib.Z_OK)
throw new ZStreamException((compress?"de":"in")+"flating: "+z.msg);
out.write(buf, 0, bufsize-z.avail_out);
}
while(z.avail_in>0 || z.avail_out==0);
}
 
public int getFlushMode() {
return(flush);
}
 
public void setFlushMode(int flush) {
this.flush=flush;
}
 
public void finish() throws IOException {
int err;
do{
z.next_out=buf;
z.next_out_index=0;
z.avail_out=bufsize;
if(compress){ err=z.deflate(JZlib.Z_FINISH); }
else{ err=z.inflate(JZlib.Z_FINISH); }
if(err!=JZlib.Z_STREAM_END && err != JZlib.Z_OK)
throw new ZStreamException((compress?"de":"in")+"flating: "+z.msg);
if(bufsize-z.avail_out>0){
out.write(buf, 0, bufsize-z.avail_out);
}
}
while(z.avail_in>0 || z.avail_out==0);
flush();
}
public void end() {
if(z==null)
return;
if(compress){ z.deflateEnd(); }
else{ z.inflateEnd(); }
z.free();
z=null;
}
public void close() throws IOException {
try{
try{finish();}
catch (IOException ignored) {}
}
finally{
end();
out.close();
out=null;
}
}
 
/**
* Returns the total number of bytes input so far.
*/
public long getTotalIn() {
return z.total_in;
}
 
/**
* Returns the total number of bytes output so far.
*/
public long getTotalOut() {
return z.total_out;
}
 
public void flush() throws IOException {
out.flush();
}
 
}
/trunk/OpenConcerto/src/com/jcraft/jzlib/StaticTree.java
New file
0,0 → 1,149
/* -*-mode:java; c-basic-offset:2; -*- */
/*
Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
 
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program is based on zlib-1.1.3, so all credit should go authors
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
* and contributors of zlib.
*/
 
package com.jcraft.jzlib;
 
final class StaticTree{
static final private int MAX_BITS=15;
 
static final private int BL_CODES=19;
static final private int D_CODES=30;
static final private int LITERALS=256;
static final private int LENGTH_CODES=29;
static final private int L_CODES=(LITERALS+1+LENGTH_CODES);
 
// Bit length codes must not exceed MAX_BL_BITS bits
static final int MAX_BL_BITS=7;
 
static final short[] static_ltree = {
12, 8, 140, 8, 76, 8, 204, 8, 44, 8,
172, 8, 108, 8, 236, 8, 28, 8, 156, 8,
92, 8, 220, 8, 60, 8, 188, 8, 124, 8,
252, 8, 2, 8, 130, 8, 66, 8, 194, 8,
34, 8, 162, 8, 98, 8, 226, 8, 18, 8,
146, 8, 82, 8, 210, 8, 50, 8, 178, 8,
114, 8, 242, 8, 10, 8, 138, 8, 74, 8,
202, 8, 42, 8, 170, 8, 106, 8, 234, 8,
26, 8, 154, 8, 90, 8, 218, 8, 58, 8,
186, 8, 122, 8, 250, 8, 6, 8, 134, 8,
70, 8, 198, 8, 38, 8, 166, 8, 102, 8,
230, 8, 22, 8, 150, 8, 86, 8, 214, 8,
54, 8, 182, 8, 118, 8, 246, 8, 14, 8,
142, 8, 78, 8, 206, 8, 46, 8, 174, 8,
110, 8, 238, 8, 30, 8, 158, 8, 94, 8,
222, 8, 62, 8, 190, 8, 126, 8, 254, 8,
1, 8, 129, 8, 65, 8, 193, 8, 33, 8,
161, 8, 97, 8, 225, 8, 17, 8, 145, 8,
81, 8, 209, 8, 49, 8, 177, 8, 113, 8,
241, 8, 9, 8, 137, 8, 73, 8, 201, 8,
41, 8, 169, 8, 105, 8, 233, 8, 25, 8,
153, 8, 89, 8, 217, 8, 57, 8, 185, 8,
121, 8, 249, 8, 5, 8, 133, 8, 69, 8,
197, 8, 37, 8, 165, 8, 101, 8, 229, 8,
21, 8, 149, 8, 85, 8, 213, 8, 53, 8,
181, 8, 117, 8, 245, 8, 13, 8, 141, 8,
77, 8, 205, 8, 45, 8, 173, 8, 109, 8,
237, 8, 29, 8, 157, 8, 93, 8, 221, 8,
61, 8, 189, 8, 125, 8, 253, 8, 19, 9,
275, 9, 147, 9, 403, 9, 83, 9, 339, 9,
211, 9, 467, 9, 51, 9, 307, 9, 179, 9,
435, 9, 115, 9, 371, 9, 243, 9, 499, 9,
11, 9, 267, 9, 139, 9, 395, 9, 75, 9,
331, 9, 203, 9, 459, 9, 43, 9, 299, 9,
171, 9, 427, 9, 107, 9, 363, 9, 235, 9,
491, 9, 27, 9, 283, 9, 155, 9, 411, 9,
91, 9, 347, 9, 219, 9, 475, 9, 59, 9,
315, 9, 187, 9, 443, 9, 123, 9, 379, 9,
251, 9, 507, 9, 7, 9, 263, 9, 135, 9,
391, 9, 71, 9, 327, 9, 199, 9, 455, 9,
39, 9, 295, 9, 167, 9, 423, 9, 103, 9,
359, 9, 231, 9, 487, 9, 23, 9, 279, 9,
151, 9, 407, 9, 87, 9, 343, 9, 215, 9,
471, 9, 55, 9, 311, 9, 183, 9, 439, 9,
119, 9, 375, 9, 247, 9, 503, 9, 15, 9,
271, 9, 143, 9, 399, 9, 79, 9, 335, 9,
207, 9, 463, 9, 47, 9, 303, 9, 175, 9,
431, 9, 111, 9, 367, 9, 239, 9, 495, 9,
31, 9, 287, 9, 159, 9, 415, 9, 95, 9,
351, 9, 223, 9, 479, 9, 63, 9, 319, 9,
191, 9, 447, 9, 127, 9, 383, 9, 255, 9,
511, 9, 0, 7, 64, 7, 32, 7, 96, 7,
16, 7, 80, 7, 48, 7, 112, 7, 8, 7,
72, 7, 40, 7, 104, 7, 24, 7, 88, 7,
56, 7, 120, 7, 4, 7, 68, 7, 36, 7,
100, 7, 20, 7, 84, 7, 52, 7, 116, 7,
3, 8, 131, 8, 67, 8, 195, 8, 35, 8,
163, 8, 99, 8, 227, 8
};
 
static final short[] static_dtree = {
0, 5, 16, 5, 8, 5, 24, 5, 4, 5,
20, 5, 12, 5, 28, 5, 2, 5, 18, 5,
10, 5, 26, 5, 6, 5, 22, 5, 14, 5,
30, 5, 1, 5, 17, 5, 9, 5, 25, 5,
5, 5, 21, 5, 13, 5, 29, 5, 3, 5,
19, 5, 11, 5, 27, 5, 7, 5, 23, 5
};
 
static StaticTree static_l_desc =
new StaticTree(static_ltree, Tree.extra_lbits,
LITERALS+1, L_CODES, MAX_BITS);
 
static StaticTree static_d_desc =
new StaticTree(static_dtree, Tree.extra_dbits,
0, D_CODES, MAX_BITS);
 
static StaticTree static_bl_desc =
new StaticTree(null, Tree.extra_blbits,
0, BL_CODES, MAX_BL_BITS);
 
short[] static_tree; // static tree or null
int[] extra_bits; // extra bits for each code or null
int extra_base; // base index for extra_bits
int elems; // max number of elements in the tree
int max_length; // max bit length for the codes
 
StaticTree(short[] static_tree,
int[] extra_bits,
int extra_base,
int elems,
int max_length
){
this.static_tree=static_tree;
this.extra_bits=extra_bits;
this.extra_base=extra_base;
this.elems=elems;
this.max_length=max_length;
}
}
/trunk/OpenConcerto/src/com/jcraft/jzlib/InfBlocks.java
New file
0,0 → 1,614
/* -*-mode:java; c-basic-offset:2; -*- */
/*
Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
 
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program is based on zlib-1.1.3, so all credit should go authors
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
* and contributors of zlib.
*/
 
package com.jcraft.jzlib;
 
final class InfBlocks{
static final private int MANY=1440;
 
// And'ing with mask[n] masks the lower n bits
static final private int[] inflate_mask = {
0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff,
0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
0x00007fff, 0x0000ffff
};
 
// Table for deflate from PKZIP's appnote.txt.
static final int[] border = { // Order of the bit length code lengths
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
};
 
static final private int Z_OK=0;
static final private int Z_STREAM_END=1;
static final private int Z_NEED_DICT=2;
static final private int Z_ERRNO=-1;
static final private int Z_STREAM_ERROR=-2;
static final private int Z_DATA_ERROR=-3;
static final private int Z_MEM_ERROR=-4;
static final private int Z_BUF_ERROR=-5;
static final private int Z_VERSION_ERROR=-6;
 
static final private int TYPE=0; // get type bits (3, including end bit)
static final private int LENS=1; // get lengths for stored
static final private int STORED=2;// processing stored block
static final private int TABLE=3; // get table lengths
static final private int BTREE=4; // get bit lengths tree for a dynamic block
static final private int DTREE=5; // get length, distance trees for a dynamic block
static final private int CODES=6; // processing fixed or dynamic block
static final private int DRY=7; // output remaining window bytes
static final private int DONE=8; // finished last block, done
static final private int BAD=9; // ot a data error--stuck here
 
int mode; // current inflate_block mode
 
int left; // if STORED, bytes left to copy
 
int table; // table lengths (14 bits)
int index; // index into blens (or border)
int[] blens; // bit lengths of codes
int[] bb=new int[1]; // bit length tree depth
int[] tb=new int[1]; // bit length decoding tree
 
InfCodes codes=new InfCodes(); // if CODES, current state
 
int last; // true if this block is the last block
 
// mode independent information
int bitk; // bits in bit buffer
int bitb; // bit buffer
int[] hufts; // single malloc for tree space
byte[] window; // sliding window
int end; // one byte after sliding window
int read; // window read pointer
int write; // window write pointer
Object checkfn; // check function
long check; // check on output
 
InfTree inftree=new InfTree();
 
InfBlocks(ZStream z, Object checkfn, int w){
hufts=new int[MANY*3];
window=new byte[w];
end=w;
this.checkfn = checkfn;
mode = TYPE;
reset(z, null);
}
 
void reset(ZStream z, long[] c){
if(c!=null) c[0]=check;
if(mode==BTREE || mode==DTREE){
}
if(mode==CODES){
codes.free(z);
}
mode=TYPE;
bitk=0;
bitb=0;
read=write=0;
 
if(checkfn != null)
z.adler=check=z._adler.adler32(0L, null, 0, 0);
}
 
int proc(ZStream z, int r){
int t; // temporary storage
int b; // bit buffer
int k; // bits in bit buffer
int p; // input data pointer
int n; // bytes available there
int q; // output window write pointer
int m; // bytes to end of window or read pointer
 
// copy input/output information to locals (UPDATE macro restores)
{p=z.next_in_index;n=z.avail_in;b=bitb;k=bitk;}
{q=write;m=(int)(q<read?read-q-1:end-q);}
 
// process input based on current state
while(true){
switch (mode){
case TYPE:
 
while(k<(3)){
if(n!=0){
r=Z_OK;
}
else{
bitb=b; bitk=k;
z.avail_in=n;
z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
};
n--;
b|=(z.next_in[p++]&0xff)<<k;
k+=8;
}
t = (int)(b & 7);
last = t & 1;
 
switch (t >>> 1){
case 0: // stored
{b>>>=(3);k-=(3);}
t = k & 7; // go to byte boundary
 
{b>>>=(t);k-=(t);}
mode = LENS; // get length of stored block
break;
case 1: // fixed
{
int[] bl=new int[1];
int[] bd=new int[1];
int[][] tl=new int[1][];
int[][] td=new int[1][];
 
InfTree.inflate_trees_fixed(bl, bd, tl, td, z);
codes.init(bl[0], bd[0], tl[0], 0, td[0], 0, z);
}
 
{b>>>=(3);k-=(3);}
 
mode = CODES;
break;
case 2: // dynamic
 
{b>>>=(3);k-=(3);}
 
mode = TABLE;
break;
case 3: // illegal
 
{b>>>=(3);k-=(3);}
mode = BAD;
z.msg = "invalid block type";
r = Z_DATA_ERROR;
 
bitb=b; bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
}
break;
case LENS:
 
while(k<(32)){
if(n!=0){
r=Z_OK;
}
else{
bitb=b; bitk=k;
z.avail_in=n;
z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
};
n--;
b|=(z.next_in[p++]&0xff)<<k;
k+=8;
}
 
if ((((~b) >>> 16) & 0xffff) != (b & 0xffff)){
mode = BAD;
z.msg = "invalid stored block lengths";
r = Z_DATA_ERROR;
 
bitb=b; bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
}
left = (b & 0xffff);
b = k = 0; // dump bits
mode = left!=0 ? STORED : (last!=0 ? DRY : TYPE);
break;
case STORED:
if (n == 0){
bitb=b; bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
}
 
if(m==0){
if(q==end&&read!=0){
q=0; m=(int)(q<read?read-q-1:end-q);
}
if(m==0){
write=q;
r=inflate_flush(z,r);
q=write;m=(int)(q<read?read-q-1:end-q);
if(q==end&&read!=0){
q=0; m=(int)(q<read?read-q-1:end-q);
}
if(m==0){
bitb=b; bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
}
}
}
r=Z_OK;
 
t = left;
if(t>n) t = n;
if(t>m) t = m;
System.arraycopy(z.next_in, p, window, q, t);
p += t; n -= t;
q += t; m -= t;
if ((left -= t) != 0)
break;
mode = last!=0 ? DRY : TYPE;
break;
case TABLE:
 
while(k<(14)){
if(n!=0){
r=Z_OK;
}
else{
bitb=b; bitk=k;
z.avail_in=n;
z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
};
n--;
b|=(z.next_in[p++]&0xff)<<k;
k+=8;
}
 
table = t = (b & 0x3fff);
if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
{
mode = BAD;
z.msg = "too many length or distance symbols";
r = Z_DATA_ERROR;
 
bitb=b; bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
}
t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
if(blens==null || blens.length<t){
blens=new int[t];
}
else{
for(int i=0; i<t; i++){blens[i]=0;}
}
 
{b>>>=(14);k-=(14);}
 
index = 0;
mode = BTREE;
case BTREE:
while (index < 4 + (table >>> 10)){
while(k<(3)){
if(n!=0){
r=Z_OK;
}
else{
bitb=b; bitk=k;
z.avail_in=n;
z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
};
n--;
b|=(z.next_in[p++]&0xff)<<k;
k+=8;
}
 
blens[border[index++]] = b&7;
 
{b>>>=(3);k-=(3);}
}
 
while(index < 19){
blens[border[index++]] = 0;
}
 
bb[0] = 7;
t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z);
if (t != Z_OK){
r = t;
if (r == Z_DATA_ERROR){
blens=null;
mode = BAD;
}
 
bitb=b; bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
}
 
index = 0;
mode = DTREE;
case DTREE:
while (true){
t = table;
if(!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))){
break;
}
 
int[] h;
int i, j, c;
 
t = bb[0];
 
while(k<(t)){
if(n!=0){
r=Z_OK;
}
else{
bitb=b; bitk=k;
z.avail_in=n;
z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
};
n--;
b|=(z.next_in[p++]&0xff)<<k;
k+=8;
}
 
if(tb[0]==-1){
//System.err.println("null...");
}
 
t=hufts[(tb[0]+(b&inflate_mask[t]))*3+1];
c=hufts[(tb[0]+(b&inflate_mask[t]))*3+2];
 
if (c < 16){
b>>>=(t);k-=(t);
blens[index++] = c;
}
else { // c == 16..18
i = c == 18 ? 7 : c - 14;
j = c == 18 ? 11 : 3;
 
while(k<(t+i)){
if(n!=0){
r=Z_OK;
}
else{
bitb=b; bitk=k;
z.avail_in=n;
z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
};
n--;
b|=(z.next_in[p++]&0xff)<<k;
k+=8;
}
 
b>>>=(t);k-=(t);
 
j += (b & inflate_mask[i]);
 
b>>>=(i);k-=(i);
 
i = index;
t = table;
if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
(c == 16 && i < 1)){
blens=null;
mode = BAD;
z.msg = "invalid bit length repeat";
r = Z_DATA_ERROR;
 
bitb=b; bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
}
 
c = c == 16 ? blens[i-1] : 0;
do{
blens[i++] = c;
}
while (--j!=0);
index = i;
}
}
 
tb[0]=-1;
{
int[] bl=new int[1];
int[] bd=new int[1];
int[] tl=new int[1];
int[] td=new int[1];
bl[0] = 9; // must be <= 9 for lookahead assumptions
bd[0] = 6; // must be <= 9 for lookahead assumptions
 
t = table;
t = inftree.inflate_trees_dynamic(257 + (t & 0x1f),
1 + ((t >> 5) & 0x1f),
blens, bl, bd, tl, td, hufts, z);
 
if (t != Z_OK){
if (t == Z_DATA_ERROR){
blens=null;
mode = BAD;
}
r = t;
 
bitb=b; bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z,r);
}
codes.init(bl[0], bd[0], hufts, tl[0], hufts, td[0], z);
}
mode = CODES;
case CODES:
bitb=b; bitk=k;
z.avail_in=n; z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
 
if ((r = codes.proc(this, z, r)) != Z_STREAM_END){
return inflate_flush(z, r);
}
r = Z_OK;
codes.free(z);
 
p=z.next_in_index; n=z.avail_in;b=bitb;k=bitk;
q=write;m=(int)(q<read?read-q-1:end-q);
 
if (last==0){
mode = TYPE;
break;
}
mode = DRY;
case DRY:
write=q;
r=inflate_flush(z, r);
q=write; m=(int)(q<read?read-q-1:end-q);
if (read != write){
bitb=b; bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z, r);
}
mode = DONE;
case DONE:
r = Z_STREAM_END;
 
bitb=b; bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z, r);
case BAD:
r = Z_DATA_ERROR;
 
bitb=b; bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z, r);
 
default:
r = Z_STREAM_ERROR;
 
bitb=b; bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
write=q;
return inflate_flush(z, r);
}
}
}
 
void free(ZStream z){
reset(z, null);
window=null;
hufts=null;
//ZFREE(z, s);
}
 
void set_dictionary(byte[] d, int start, int n){
System.arraycopy(d, start, window, 0, n);
read = write = n;
}
 
// Returns true if inflate is currently at the end of a block generated
// by Z_SYNC_FLUSH or Z_FULL_FLUSH.
int sync_point(){
return mode == LENS ? 1 : 0;
}
 
// copy as much as possible from the sliding window to the output area
int inflate_flush(ZStream z, int r){
int n;
int p;
int q;
 
// local copies of source and destination pointers
p = z.next_out_index;
q = read;
 
// compute number of bytes to copy as far as end of window
n = (int)((q <= write ? write : end) - q);
if (n > z.avail_out) n = z.avail_out;
if (n!=0 && r == Z_BUF_ERROR) r = Z_OK;
 
// update counters
z.avail_out -= n;
z.total_out += n;
 
// update check information
if(checkfn != null)
z.adler=check=z._adler.adler32(check, window, q, n);
 
// copy as far as end of window
System.arraycopy(window, q, z.next_out, p, n);
p += n;
q += n;
 
// see if more to copy at beginning of window
if (q == end){
// wrap pointers
q = 0;
if (write == end)
write = 0;
 
// compute bytes to copy
n = write - q;
if (n > z.avail_out) n = z.avail_out;
if (n!=0 && r == Z_BUF_ERROR) r = Z_OK;
 
// update counters
z.avail_out -= n;
z.total_out += n;
 
// update check information
if(checkfn != null)
z.adler=check=z._adler.adler32(check, window, q, n);
 
// copy
System.arraycopy(window, q, z.next_out, p, n);
p += n;
q += n;
}
 
// update pointers
z.next_out_index = p;
read = q;
 
// done
return r;
}
}
/trunk/OpenConcerto/src/com/jcraft/jzlib/InfCodes.java
New file
0,0 → 1,605
/* -*-mode:java; c-basic-offset:2; -*- */
/*
Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
 
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program is based on zlib-1.1.3, so all credit should go authors
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
* and contributors of zlib.
*/
 
package com.jcraft.jzlib;
 
final class InfCodes{
 
static final private int[] inflate_mask = {
0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff,
0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
0x00007fff, 0x0000ffff
};
 
static final private int Z_OK=0;
static final private int Z_STREAM_END=1;
static final private int Z_NEED_DICT=2;
static final private int Z_ERRNO=-1;
static final private int Z_STREAM_ERROR=-2;
static final private int Z_DATA_ERROR=-3;
static final private int Z_MEM_ERROR=-4;
static final private int Z_BUF_ERROR=-5;
static final private int Z_VERSION_ERROR=-6;
 
// waiting for "i:"=input,
// "o:"=output,
// "x:"=nothing
static final private int START=0; // x: set up for LEN
static final private int LEN=1; // i: get length/literal/eob next
static final private int LENEXT=2; // i: getting length extra (have base)
static final private int DIST=3; // i: get distance next
static final private int DISTEXT=4;// i: getting distance extra
static final private int COPY=5; // o: copying bytes in window, waiting for space
static final private int LIT=6; // o: got literal, waiting for output space
static final private int WASH=7; // o: got eob, possibly still output waiting
static final private int END=8; // x: got eob and all data flushed
static final private int BADCODE=9;// x: got error
 
int mode; // current inflate_codes mode
 
// mode dependent information
int len;
 
int[] tree; // pointer into tree
int tree_index=0;
int need; // bits needed
 
int lit;
 
// if EXT or COPY, where and how much
int get; // bits to get for extra
int dist; // distance back to copy from
 
byte lbits; // ltree bits decoded per branch
byte dbits; // dtree bits decoder per branch
int[] ltree; // literal/length/eob tree
int ltree_index; // literal/length/eob tree
int[] dtree; // distance tree
int dtree_index; // distance tree
 
InfCodes(){
}
void init(int bl, int bd,
int[] tl, int tl_index,
int[] td, int td_index, ZStream z){
mode=START;
lbits=(byte)bl;
dbits=(byte)bd;
ltree=tl;
ltree_index=tl_index;
dtree = td;
dtree_index=td_index;
tree=null;
}
 
int proc(InfBlocks s, ZStream z, int r){
int j; // temporary storage
int[] t; // temporary pointer
int tindex; // temporary pointer
int e; // extra bits or operation
int b=0; // bit buffer
int k=0; // bits in bit buffer
int p=0; // input data pointer
int n; // bytes available there
int q; // output window write pointer
int m; // bytes to end of window or read pointer
int f; // pointer to copy strings from
 
// copy input/output information to locals (UPDATE macro restores)
p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
q=s.write;m=q<s.read?s.read-q-1:s.end-q;
 
// process input and output based on current state
while (true){
switch (mode){
// waiting for "i:"=input, "o:"=output, "x:"=nothing
case START: // x: set up for LEN
if (m >= 258 && n >= 10){
 
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
r = inflate_fast(lbits, dbits,
ltree, ltree_index,
dtree, dtree_index,
s, z);
 
p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
q=s.write;m=q<s.read?s.read-q-1:s.end-q;
 
if (r != Z_OK){
mode = r == Z_STREAM_END ? WASH : BADCODE;
break;
}
}
need = lbits;
tree = ltree;
tree_index=ltree_index;
 
mode = LEN;
case LEN: // i: get length/literal/eob next
j = need;
 
while(k<(j)){
if(n!=0)r=Z_OK;
else{
 
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
return s.inflate_flush(z,r);
}
n--;
b|=(z.next_in[p++]&0xff)<<k;
k+=8;
}
 
tindex=(tree_index+(b&inflate_mask[j]))*3;
 
b>>>=(tree[tindex+1]);
k-=(tree[tindex+1]);
 
e=tree[tindex];
 
if(e == 0){ // literal
lit = tree[tindex+2];
mode = LIT;
break;
}
if((e & 16)!=0 ){ // length
get = e & 15;
len = tree[tindex+2];
mode = LENEXT;
break;
}
if ((e & 64) == 0){ // next table
need = e;
tree_index = tindex/3+tree[tindex+2];
break;
}
if ((e & 32)!=0){ // end of block
mode = WASH;
break;
}
mode = BADCODE; // invalid code
z.msg = "invalid literal/length code";
r = Z_DATA_ERROR;
 
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
return s.inflate_flush(z,r);
 
case LENEXT: // i: getting length extra (have base)
j = get;
 
while(k<(j)){
if(n!=0)r=Z_OK;
else{
 
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
return s.inflate_flush(z,r);
}
n--; b|=(z.next_in[p++]&0xff)<<k;
k+=8;
}
 
len += (b & inflate_mask[j]);
 
b>>=j;
k-=j;
 
need = dbits;
tree = dtree;
tree_index=dtree_index;
mode = DIST;
case DIST: // i: get distance next
j = need;
 
while(k<(j)){
if(n!=0)r=Z_OK;
else{
 
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
return s.inflate_flush(z,r);
}
n--; b|=(z.next_in[p++]&0xff)<<k;
k+=8;
}
 
tindex=(tree_index+(b & inflate_mask[j]))*3;
 
b>>=tree[tindex+1];
k-=tree[tindex+1];
 
e = (tree[tindex]);
if((e & 16)!=0){ // distance
get = e & 15;
dist = tree[tindex+2];
mode = DISTEXT;
break;
}
if ((e & 64) == 0){ // next table
need = e;
tree_index = tindex/3 + tree[tindex+2];
break;
}
mode = BADCODE; // invalid code
z.msg = "invalid distance code";
r = Z_DATA_ERROR;
 
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
return s.inflate_flush(z,r);
 
case DISTEXT: // i: getting distance extra
j = get;
 
while(k<(j)){
if(n!=0)r=Z_OK;
else{
 
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
return s.inflate_flush(z,r);
}
n--; b|=(z.next_in[p++]&0xff)<<k;
k+=8;
}
 
dist += (b & inflate_mask[j]);
 
b>>=j;
k-=j;
 
mode = COPY;
case COPY: // o: copying bytes in window, waiting for space
f = q - dist;
while(f < 0){ // modulo window size-"while" instead
f += s.end; // of "if" handles invalid distances
}
while (len!=0){
 
if(m==0){
if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
if(m==0){
s.write=q; r=s.inflate_flush(z,r);
q=s.write;m=q<s.read?s.read-q-1:s.end-q;
 
if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
 
if(m==0){
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
return s.inflate_flush(z,r);
}
}
}
 
s.window[q++]=s.window[f++]; m--;
 
if (f == s.end)
f = 0;
len--;
}
mode = START;
break;
case LIT: // o: got literal, waiting for output space
if(m==0){
if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
if(m==0){
s.write=q; r=s.inflate_flush(z,r);
q=s.write;m=q<s.read?s.read-q-1:s.end-q;
 
if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
if(m==0){
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
return s.inflate_flush(z,r);
}
}
}
r=Z_OK;
 
s.window[q++]=(byte)lit; m--;
 
mode = START;
break;
case WASH: // o: got eob, possibly more output
if (k > 7){ // return unused byte, if any
k -= 8;
n++;
p--; // can always return one
}
 
s.write=q; r=s.inflate_flush(z,r);
q=s.write;m=q<s.read?s.read-q-1:s.end-q;
 
if (s.read != s.write){
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
return s.inflate_flush(z,r);
}
mode = END;
case END:
r = Z_STREAM_END;
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
return s.inflate_flush(z,r);
 
case BADCODE: // x: got error
 
r = Z_DATA_ERROR;
 
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
return s.inflate_flush(z,r);
 
default:
r = Z_STREAM_ERROR;
 
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
return s.inflate_flush(z,r);
}
}
}
 
void free(ZStream z){
// ZFREE(z, c);
}
 
// Called with number of bytes left to write in window at least 258
// (the maximum string length) and number of input bytes available
// at least ten. The ten bytes are six bytes for the longest length/
// distance pair plus four bytes for overloading the bit buffer.
 
int inflate_fast(int bl, int bd,
int[] tl, int tl_index,
int[] td, int td_index,
InfBlocks s, ZStream z){
int t; // temporary pointer
int[] tp; // temporary pointer
int tp_index; // temporary pointer
int e; // extra bits or operation
int b; // bit buffer
int k; // bits in bit buffer
int p; // input data pointer
int n; // bytes available there
int q; // output window write pointer
int m; // bytes to end of window or read pointer
int ml; // mask for literal/length tree
int md; // mask for distance tree
int c; // bytes to copy
int d; // distance back to copy from
int r; // copy source pointer
 
int tp_index_t_3; // (tp_index+t)*3
 
// load input, output, bit values
p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
q=s.write;m=q<s.read?s.read-q-1:s.end-q;
 
// initialize masks
ml = inflate_mask[bl];
md = inflate_mask[bd];
 
// do until not enough input or output space for fast loop
do { // assume called with m >= 258 && n >= 10
// get literal/length code
while(k<(20)){ // max bits for literal/length code
n--;
b|=(z.next_in[p++]&0xff)<<k;k+=8;
}
 
t= b&ml;
tp=tl;
tp_index=tl_index;
tp_index_t_3=(tp_index+t)*3;
if ((e = tp[tp_index_t_3]) == 0){
b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
 
s.window[q++] = (byte)tp[tp_index_t_3+2];
m--;
continue;
}
do {
 
b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
 
if((e&16)!=0){
e &= 15;
c = tp[tp_index_t_3+2] + ((int)b & inflate_mask[e]);
 
b>>=e; k-=e;
 
// decode distance base of block to copy
while(k<(15)){ // max bits for distance code
n--;
b|=(z.next_in[p++]&0xff)<<k;k+=8;
}
 
t= b&md;
tp=td;
tp_index=td_index;
tp_index_t_3=(tp_index+t)*3;
e = tp[tp_index_t_3];
 
do {
 
b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
 
if((e&16)!=0){
// get extra bits to add to distance base
e &= 15;
while(k<(e)){ // get extra bits (up to 13)
n--;
b|=(z.next_in[p++]&0xff)<<k;k+=8;
}
 
d = tp[tp_index_t_3+2] + (b&inflate_mask[e]);
 
b>>=(e); k-=(e);
 
// do the copy
m -= c;
if (q >= d){ // offset before dest
// just copy
r=q-d;
if(q-r>0 && 2>(q-r)){
s.window[q++]=s.window[r++]; // minimum count is three,
s.window[q++]=s.window[r++]; // so unroll loop a little
c-=2;
}
else{
System.arraycopy(s.window, r, s.window, q, 2);
q+=2; r+=2; c-=2;
}
}
else{ // else offset after destination
r=q-d;
do{
r+=s.end; // force pointer in window
}while(r<0); // covers invalid distances
e=s.end-r;
if(c>e){ // if source crosses,
c-=e; // wrapped copy
if(q-r>0 && e>(q-r)){
do{s.window[q++] = s.window[r++];}
while(--e!=0);
}
else{
System.arraycopy(s.window, r, s.window, q, e);
q+=e; r+=e; e=0;
}
r = 0; // copy rest from start of window
}
 
}
 
// copy all or what's left
if(q-r>0 && c>(q-r)){
do{s.window[q++] = s.window[r++];}
while(--c!=0);
}
else{
System.arraycopy(s.window, r, s.window, q, c);
q+=c; r+=c; c=0;
}
break;
}
else if((e&64)==0){
t+=tp[tp_index_t_3+2];
t+=(b&inflate_mask[e]);
tp_index_t_3=(tp_index+t)*3;
e=tp[tp_index_t_3];
}
else{
z.msg = "invalid distance code";
 
c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
 
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
 
return Z_DATA_ERROR;
}
}
while(true);
break;
}
 
if((e&64)==0){
t+=tp[tp_index_t_3+2];
t+=(b&inflate_mask[e]);
tp_index_t_3=(tp_index+t)*3;
if((e=tp[tp_index_t_3])==0){
 
b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
 
s.window[q++]=(byte)tp[tp_index_t_3+2];
m--;
break;
}
}
else if((e&32)!=0){
 
c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
 
return Z_STREAM_END;
}
else{
z.msg="invalid literal/length code";
 
c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
 
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
 
return Z_DATA_ERROR;
}
}
while(true);
}
while(m>=258 && n>= 10);
 
// not enough input or output--restore pointers and return
c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
 
s.bitb=b;s.bitk=k;
z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
s.write=q;
 
return Z_OK;
}
}
/trunk/OpenConcerto/src/com/jcraft/jzlib/JZlib.java
New file
0,0 → 1,67
/* -*-mode:java; c-basic-offset:2; -*- */
/*
Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
 
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program is based on zlib-1.1.3, so all credit should go authors
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
* and contributors of zlib.
*/
 
package com.jcraft.jzlib;
 
final public class JZlib{
private static final String version="1.0.2";
public static String version(){return version;}
 
// compression levels
static final public int Z_NO_COMPRESSION=0;
static final public int Z_BEST_SPEED=1;
static final public int Z_BEST_COMPRESSION=9;
static final public int Z_DEFAULT_COMPRESSION=(-1);
 
// compression strategy
static final public int Z_FILTERED=1;
static final public int Z_HUFFMAN_ONLY=2;
static final public int Z_DEFAULT_STRATEGY=0;
 
static final public int Z_NO_FLUSH=0;
static final public int Z_PARTIAL_FLUSH=1;
static final public int Z_SYNC_FLUSH=2;
static final public int Z_FULL_FLUSH=3;
static final public int Z_FINISH=4;
 
static final public int Z_OK=0;
static final public int Z_STREAM_END=1;
static final public int Z_NEED_DICT=2;
static final public int Z_ERRNO=-1;
static final public int Z_STREAM_ERROR=-2;
static final public int Z_DATA_ERROR=-3;
static final public int Z_MEM_ERROR=-4;
static final public int Z_BUF_ERROR=-5;
static final public int Z_VERSION_ERROR=-6;
}
/trunk/OpenConcerto/src/com/jcraft/jzlib/Adler32.java
New file
0,0 → 1,94
/* -*-mode:java; c-basic-offset:2; -*- */
/*
Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
 
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program is based on zlib-1.1.3, so all credit should go authors
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
* and contributors of zlib.
*/
 
package com.jcraft.jzlib;
 
final class Adler32{
 
// largest prime smaller than 65536
static final private int BASE=65521;
// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
static final private int NMAX=5552;
 
long adler32(long adler, byte[] buf, int index, int len){
if(buf == null){ return 1L; }
 
long s1=adler&0xffff;
long s2=(adler>>16)&0xffff;
int k;
 
while(len > 0) {
k=len<NMAX?len:NMAX;
len-=k;
while(k>=16){
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
s1+=buf[index++]&0xff; s2+=s1;
k-=16;
}
if(k!=0){
do{
s1+=buf[index++]&0xff; s2+=s1;
}
while(--k!=0);
}
s1%=BASE;
s2%=BASE;
}
return (s2<<16)|s1;
}
 
/*
private java.util.zip.Adler32 adler=new java.util.zip.Adler32();
long adler32(long value, byte[] buf, int index, int len){
if(value==1) {adler.reset();}
if(buf==null) {adler.reset();}
else{adler.update(buf, index, len);}
return adler.getValue();
}
*/
}
/trunk/OpenConcerto/src/com/jcraft/jzlib/InfTree.java
New file
0,0 → 1,520
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/*
Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
 
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program is based on zlib-1.1.3, so all credit should go authors
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
* and contributors of zlib.
*/
 
package com.jcraft.jzlib;
 
final class InfTree{
 
static final private int MANY=1440;
 
static final private int Z_OK=0;
static final private int Z_STREAM_END=1;
static final private int Z_NEED_DICT=2;
static final private int Z_ERRNO=-1;
static final private int Z_STREAM_ERROR=-2;
static final private int Z_DATA_ERROR=-3;
static final private int Z_MEM_ERROR=-4;
static final private int Z_BUF_ERROR=-5;
static final private int Z_VERSION_ERROR=-6;
 
static final int fixed_bl = 9;
static final int fixed_bd = 5;
 
static final int[] fixed_tl = {
96,7,256, 0,8,80, 0,8,16, 84,8,115,
82,7,31, 0,8,112, 0,8,48, 0,9,192,
80,7,10, 0,8,96, 0,8,32, 0,9,160,
0,8,0, 0,8,128, 0,8,64, 0,9,224,
80,7,6, 0,8,88, 0,8,24, 0,9,144,
83,7,59, 0,8,120, 0,8,56, 0,9,208,
81,7,17, 0,8,104, 0,8,40, 0,9,176,
0,8,8, 0,8,136, 0,8,72, 0,9,240,
80,7,4, 0,8,84, 0,8,20, 85,8,227,
83,7,43, 0,8,116, 0,8,52, 0,9,200,
81,7,13, 0,8,100, 0,8,36, 0,9,168,
0,8,4, 0,8,132, 0,8,68, 0,9,232,
80,7,8, 0,8,92, 0,8,28, 0,9,152,
84,7,83, 0,8,124, 0,8,60, 0,9,216,
82,7,23, 0,8,108, 0,8,44, 0,9,184,
0,8,12, 0,8,140, 0,8,76, 0,9,248,
80,7,3, 0,8,82, 0,8,18, 85,8,163,
83,7,35, 0,8,114, 0,8,50, 0,9,196,
81,7,11, 0,8,98, 0,8,34, 0,9,164,
0,8,2, 0,8,130, 0,8,66, 0,9,228,
80,7,7, 0,8,90, 0,8,26, 0,9,148,
84,7,67, 0,8,122, 0,8,58, 0,9,212,
82,7,19, 0,8,106, 0,8,42, 0,9,180,
0,8,10, 0,8,138, 0,8,74, 0,9,244,
80,7,5, 0,8,86, 0,8,22, 192,8,0,
83,7,51, 0,8,118, 0,8,54, 0,9,204,
81,7,15, 0,8,102, 0,8,38, 0,9,172,
0,8,6, 0,8,134, 0,8,70, 0,9,236,
80,7,9, 0,8,94, 0,8,30, 0,9,156,
84,7,99, 0,8,126, 0,8,62, 0,9,220,
82,7,27, 0,8,110, 0,8,46, 0,9,188,
0,8,14, 0,8,142, 0,8,78, 0,9,252,
96,7,256, 0,8,81, 0,8,17, 85,8,131,
82,7,31, 0,8,113, 0,8,49, 0,9,194,
80,7,10, 0,8,97, 0,8,33, 0,9,162,
0,8,1, 0,8,129, 0,8,65, 0,9,226,
80,7,6, 0,8,89, 0,8,25, 0,9,146,
83,7,59, 0,8,121, 0,8,57, 0,9,210,
81,7,17, 0,8,105, 0,8,41, 0,9,178,
0,8,9, 0,8,137, 0,8,73, 0,9,242,
80,7,4, 0,8,85, 0,8,21, 80,8,258,
83,7,43, 0,8,117, 0,8,53, 0,9,202,
81,7,13, 0,8,101, 0,8,37, 0,9,170,
0,8,5, 0,8,133, 0,8,69, 0,9,234,
80,7,8, 0,8,93, 0,8,29, 0,9,154,
84,7,83, 0,8,125, 0,8,61, 0,9,218,
82,7,23, 0,8,109, 0,8,45, 0,9,186,
0,8,13, 0,8,141, 0,8,77, 0,9,250,
80,7,3, 0,8,83, 0,8,19, 85,8,195,
83,7,35, 0,8,115, 0,8,51, 0,9,198,
81,7,11, 0,8,99, 0,8,35, 0,9,166,
0,8,3, 0,8,131, 0,8,67, 0,9,230,
80,7,7, 0,8,91, 0,8,27, 0,9,150,
84,7,67, 0,8,123, 0,8,59, 0,9,214,
82,7,19, 0,8,107, 0,8,43, 0,9,182,
0,8,11, 0,8,139, 0,8,75, 0,9,246,
80,7,5, 0,8,87, 0,8,23, 192,8,0,
83,7,51, 0,8,119, 0,8,55, 0,9,206,
81,7,15, 0,8,103, 0,8,39, 0,9,174,
0,8,7, 0,8,135, 0,8,71, 0,9,238,
80,7,9, 0,8,95, 0,8,31, 0,9,158,
84,7,99, 0,8,127, 0,8,63, 0,9,222,
82,7,27, 0,8,111, 0,8,47, 0,9,190,
0,8,15, 0,8,143, 0,8,79, 0,9,254,
96,7,256, 0,8,80, 0,8,16, 84,8,115,
82,7,31, 0,8,112, 0,8,48, 0,9,193,
 
80,7,10, 0,8,96, 0,8,32, 0,9,161,
0,8,0, 0,8,128, 0,8,64, 0,9,225,
80,7,6, 0,8,88, 0,8,24, 0,9,145,
83,7,59, 0,8,120, 0,8,56, 0,9,209,
81,7,17, 0,8,104, 0,8,40, 0,9,177,
0,8,8, 0,8,136, 0,8,72, 0,9,241,
80,7,4, 0,8,84, 0,8,20, 85,8,227,
83,7,43, 0,8,116, 0,8,52, 0,9,201,
81,7,13, 0,8,100, 0,8,36, 0,9,169,
0,8,4, 0,8,132, 0,8,68, 0,9,233,
80,7,8, 0,8,92, 0,8,28, 0,9,153,
84,7,83, 0,8,124, 0,8,60, 0,9,217,
82,7,23, 0,8,108, 0,8,44, 0,9,185,
0,8,12, 0,8,140, 0,8,76, 0,9,249,
80,7,3, 0,8,82, 0,8,18, 85,8,163,
83,7,35, 0,8,114, 0,8,50, 0,9,197,
81,7,11, 0,8,98, 0,8,34, 0,9,165,
0,8,2, 0,8,130, 0,8,66, 0,9,229,
80,7,7, 0,8,90, 0,8,26, 0,9,149,
84,7,67, 0,8,122, 0,8,58, 0,9,213,
82,7,19, 0,8,106, 0,8,42, 0,9,181,
0,8,10, 0,8,138, 0,8,74, 0,9,245,
80,7,5, 0,8,86, 0,8,22, 192,8,0,
83,7,51, 0,8,118, 0,8,54, 0,9,205,
81,7,15, 0,8,102, 0,8,38, 0,9,173,
0,8,6, 0,8,134, 0,8,70, 0,9,237,
80,7,9, 0,8,94, 0,8,30, 0,9,157,
84,7,99, 0,8,126, 0,8,62, 0,9,221,
82,7,27, 0,8,110, 0,8,46, 0,9,189,
0,8,14, 0,8,142, 0,8,78, 0,9,253,
96,7,256, 0,8,81, 0,8,17, 85,8,131,
82,7,31, 0,8,113, 0,8,49, 0,9,195,
80,7,10, 0,8,97, 0,8,33, 0,9,163,
0,8,1, 0,8,129, 0,8,65, 0,9,227,
80,7,6, 0,8,89, 0,8,25, 0,9,147,
83,7,59, 0,8,121, 0,8,57, 0,9,211,
81,7,17, 0,8,105, 0,8,41, 0,9,179,
0,8,9, 0,8,137, 0,8,73, 0,9,243,
80,7,4, 0,8,85, 0,8,21, 80,8,258,
83,7,43, 0,8,117, 0,8,53, 0,9,203,
81,7,13, 0,8,101, 0,8,37, 0,9,171,
0,8,5, 0,8,133, 0,8,69, 0,9,235,
80,7,8, 0,8,93, 0,8,29, 0,9,155,
84,7,83, 0,8,125, 0,8,61, 0,9,219,
82,7,23, 0,8,109, 0,8,45, 0,9,187,
0,8,13, 0,8,141, 0,8,77, 0,9,251,
80,7,3, 0,8,83, 0,8,19, 85,8,195,
83,7,35, 0,8,115, 0,8,51, 0,9,199,
81,7,11, 0,8,99, 0,8,35, 0,9,167,
0,8,3, 0,8,131, 0,8,67, 0,9,231,
80,7,7, 0,8,91, 0,8,27, 0,9,151,
84,7,67, 0,8,123, 0,8,59, 0,9,215,
82,7,19, 0,8,107, 0,8,43, 0,9,183,
0,8,11, 0,8,139, 0,8,75, 0,9,247,
80,7,5, 0,8,87, 0,8,23, 192,8,0,
83,7,51, 0,8,119, 0,8,55, 0,9,207,
81,7,15, 0,8,103, 0,8,39, 0,9,175,
0,8,7, 0,8,135, 0,8,71, 0,9,239,
80,7,9, 0,8,95, 0,8,31, 0,9,159,
84,7,99, 0,8,127, 0,8,63, 0,9,223,
82,7,27, 0,8,111, 0,8,47, 0,9,191,
0,8,15, 0,8,143, 0,8,79, 0,9,255
};
static final int[] fixed_td = {
80,5,1, 87,5,257, 83,5,17, 91,5,4097,
81,5,5, 89,5,1025, 85,5,65, 93,5,16385,
80,5,3, 88,5,513, 84,5,33, 92,5,8193,
82,5,9, 90,5,2049, 86,5,129, 192,5,24577,
80,5,2, 87,5,385, 83,5,25, 91,5,6145,
81,5,7, 89,5,1537, 85,5,97, 93,5,24577,
80,5,4, 88,5,769, 84,5,49, 92,5,12289,
82,5,13, 90,5,3073, 86,5,193, 192,5,24577
};
 
// Tables for deflate from PKZIP's appnote.txt.
static final int[] cplens = { // Copy lengths for literal codes 257..285
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
};
 
// see note #13 above about 258
static final int[] cplext = { // Extra bits for literal codes 257..285
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 // 112==invalid
};
 
static final int[] cpdist = { // Copy offsets for distance codes 0..29
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577
};
 
static final int[] cpdext = { // Extra bits for distance codes
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
12, 12, 13, 13};
 
// If BMAX needs to be larger than 16, then h and x[] should be uLong.
static final int BMAX=15; // maximum bit length of any code
 
int[] hn = null; // hufts used in space
int[] v = null; // work area for huft_build
int[] c = null; // bit length count table
int[] r = null; // table entry for structure assignment
int[] u = null; // table stack
int[] x = null; // bit offsets, then code stack
 
private int huft_build(int[] b, // code lengths in bits (all assumed <= BMAX)
int bindex,
int n, // number of codes (assumed <= 288)
int s, // number of simple-valued codes (0..s-1)
int[] d, // list of base values for non-simple codes
int[] e, // list of extra bits for non-simple codes
int[] t, // result: starting table
int[] m, // maximum lookup bits, returns actual
int[] hp,// space for trees
int[] hn,// hufts used in space
int[] v // working area: values in order of bit length
){
// Given a list of code lengths and a maximum table size, make a set of
// tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
// if the given code set is incomplete (the tables are still built in this
// case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
// lengths), or Z_MEM_ERROR if not enough memory.
 
int a; // counter for codes of length k
int f; // i repeats in table every f entries
int g; // maximum code length
int h; // table level
int i; // counter, current code
int j; // counter
int k; // number of bits in current code
int l; // bits per table (returned in m)
int mask; // (1 << w) - 1, to avoid cc -O bug on HP
int p; // pointer into c[], b[], or v[]
int q; // points to current table
int w; // bits before this table == (l * h)
int xp; // pointer into x
int y; // number of dummy codes added
int z; // number of entries in current table
 
// Generate counts for each bit length
 
p = 0; i = n;
do {
c[b[bindex+p]]++; p++; i--; // assume all entries <= BMAX
}while(i!=0);
 
if(c[0] == n){ // null input--all zero length codes
t[0] = -1;
m[0] = 0;
return Z_OK;
}
 
// Find minimum and maximum length, bound *m by those
l = m[0];
for (j = 1; j <= BMAX; j++)
if(c[j]!=0) break;
k = j; // minimum code length
if(l < j){
l = j;
}
for (i = BMAX; i!=0; i--){
if(c[i]!=0) break;
}
g = i; // maximum code length
if(l > i){
l = i;
}
m[0] = l;
 
// Adjust last length count to fill out codes, if needed
for (y = 1 << j; j < i; j++, y <<= 1){
if ((y -= c[j]) < 0){
return Z_DATA_ERROR;
}
}
if ((y -= c[i]) < 0){
return Z_DATA_ERROR;
}
c[i] += y;
 
// Generate starting offsets into the value table for each length
x[1] = j = 0;
p = 1; xp = 2;
while (--i!=0) { // note that i == g from above
x[xp] = (j += c[p]);
xp++;
p++;
}
 
// Make a table of values in order of bit lengths
i = 0; p = 0;
do {
if ((j = b[bindex+p]) != 0){
v[x[j]++] = i;
}
p++;
}
while (++i < n);
n = x[g]; // set n to length of v
 
// Generate the Huffman codes and for each, make the table entries
x[0] = i = 0; // first Huffman code is zero
p = 0; // grab values in bit order
h = -1; // no tables yet--level -1
w = -l; // bits decoded == (l * h)
u[0] = 0; // just to keep compilers happy
q = 0; // ditto
z = 0; // ditto
 
// go through the bit lengths (k already is bits in shortest code)
for (; k <= g; k++){
a = c[k];
while (a--!=0){
// here i is the Huffman code of length k bits for value *p
// make tables up to required level
while (k > w + l){
h++;
w += l; // previous table always l bits
// compute minimum size table less than or equal to l bits
z = g - w;
z = (z > l) ? l : z; // table size upper limit
if((f=1<<(j=k-w))>a+1){ // try a k-w bit table
// too few codes for k-w bit table
f -= a + 1; // deduct codes from patterns left
xp = k;
if(j < z){
while (++j < z){ // try smaller tables up to z bits
if((f <<= 1) <= c[++xp])
break; // enough codes to use up j bits
f -= c[xp]; // else deduct codes from patterns
}
}
}
z = 1 << j; // table entries for j-bit table
 
// allocate new table
if (hn[0] + z > MANY){ // (note: doesn't matter for fixed)
return Z_DATA_ERROR; // overflow of MANY
}
u[h] = q = /*hp+*/ hn[0]; // DEBUG
hn[0] += z;
// connect to last table, if there is one
if(h!=0){
x[h]=i; // save pattern for backing up
r[0]=(byte)j; // bits in this table
r[1]=(byte)l; // bits to dump before this table
j=i>>>(w - l);
r[2] = (int)(q - u[h-1] - j); // offset to this table
System.arraycopy(r, 0, hp, (u[h-1]+j)*3, 3); // connect to last table
}
else{
t[0] = q; // first table is returned result
}
}
 
// set up table entry in r
r[1] = (byte)(k - w);
if (p >= n){
r[0] = 128 + 64; // out of values--invalid code
}
else if (v[p] < s){
r[0] = (byte)(v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block
r[2] = v[p++]; // simple code is just the value
}
else{
r[0]=(byte)(e[v[p]-s]+16+64); // non-simple--look up in lists
r[2]=d[v[p++] - s];
}
 
// fill code-like entries with r
f=1<<(k-w);
for (j=i>>>w;j<z;j+=f){
System.arraycopy(r, 0, hp, (q+j)*3, 3);
}
 
// backwards increment the k-bit code i
for (j = 1 << (k - 1); (i & j)!=0; j >>>= 1){
i ^= j;
}
i ^= j;
 
// backup over finished tables
mask = (1 << w) - 1; // needed on HP, cc -O bug
while ((i & mask) != x[h]){
h--; // don't need to update q
w -= l;
mask = (1 << w) - 1;
}
}
}
// Return Z_BUF_ERROR if we were given an incomplete table
return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
}
 
int inflate_trees_bits(int[] c, // 19 code lengths
int[] bb, // bits tree desired/actual depth
int[] tb, // bits tree result
int[] hp, // space for trees
ZStream z // for messages
){
int result;
initWorkArea(19);
hn[0]=0;
result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
 
if(result == Z_DATA_ERROR){
z.msg = "oversubscribed dynamic bit lengths tree";
}
else if(result == Z_BUF_ERROR || bb[0] == 0){
z.msg = "incomplete dynamic bit lengths tree";
result = Z_DATA_ERROR;
}
return result;
}
 
int inflate_trees_dynamic(int nl, // number of literal/length codes
int nd, // number of distance codes
int[] c, // that many (total) code lengths
int[] bl, // literal desired/actual bit depth
int[] bd, // distance desired/actual bit depth
int[] tl, // literal/length tree result
int[] td, // distance tree result
int[] hp, // space for trees
ZStream z // for messages
){
int result;
 
// build literal/length tree
initWorkArea(288);
hn[0]=0;
result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
if (result != Z_OK || bl[0] == 0){
if(result == Z_DATA_ERROR){
z.msg = "oversubscribed literal/length tree";
}
else if (result != Z_MEM_ERROR){
z.msg = "incomplete literal/length tree";
result = Z_DATA_ERROR;
}
return result;
}
 
// build distance tree
initWorkArea(288);
result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
 
if (result != Z_OK || (bd[0] == 0 && nl > 257)){
if (result == Z_DATA_ERROR){
z.msg = "oversubscribed distance tree";
}
else if (result == Z_BUF_ERROR) {
z.msg = "incomplete distance tree";
result = Z_DATA_ERROR;
}
else if (result != Z_MEM_ERROR){
z.msg = "empty distance tree with lengths";
result = Z_DATA_ERROR;
}
return result;
}
 
return Z_OK;
}
 
static int inflate_trees_fixed(int[] bl, //literal desired/actual bit depth
int[] bd, //distance desired/actual bit depth
int[][] tl,//literal/length tree result
int[][] td,//distance tree result
ZStream z //for memory allocation
){
bl[0]=fixed_bl;
bd[0]=fixed_bd;
tl[0]=fixed_tl;
td[0]=fixed_td;
return Z_OK;
}
 
private void initWorkArea(int vsize){
if(hn==null){
hn=new int[1];
v=new int[vsize];
c=new int[BMAX+1];
r=new int[3];
u=new int[BMAX];
x=new int[BMAX+1];
}
if(v.length<vsize){ v=new int[vsize]; }
for(int i=0; i<vsize; i++){v[i]=0;}
for(int i=0; i<BMAX+1; i++){c[i]=0;}
for(int i=0; i<3; i++){r[i]=0;}
// for(int i=0; i<BMAX; i++){u[i]=0;}
System.arraycopy(c, 0, u, 0, BMAX);
// for(int i=0; i<BMAX+1; i++){x[i]=0;}
System.arraycopy(c, 0, x, 0, BMAX+1);
}
}
/trunk/OpenConcerto/src/com/jcraft/jzlib/Tree.java
New file
0,0 → 1,365
/* -*-mode:java; c-basic-offset:2; -*- */
/*
Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
 
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
 
3. The names of the authors may not be used to endorse or promote products
derived from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This program is based on zlib-1.1.3, so all credit should go authors
* Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
* and contributors of zlib.
*/
 
package com.jcraft.jzlib;
 
final class Tree{
static final private int MAX_BITS=15;
static final private int BL_CODES=19;
static final private int D_CODES=30;
static final private int LITERALS=256;
static final private int LENGTH_CODES=29;
static final private int L_CODES=(LITERALS+1+LENGTH_CODES);
static final private int HEAP_SIZE=(2*L_CODES+1);
 
// Bit length codes must not exceed MAX_BL_BITS bits
static final int MAX_BL_BITS=7;
 
// end of block literal code
static final int END_BLOCK=256;
 
// repeat previous bit length 3-6 times (2 bits of repeat count)
static final int REP_3_6=16;
 
// repeat a zero length 3-10 times (3 bits of repeat count)
static final int REPZ_3_10=17;
 
// repeat a zero length 11-138 times (7 bits of repeat count)
static final int REPZ_11_138=18;
 
// extra bits for each length code
static final int[] extra_lbits={
0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0
};
 
// extra bits for each distance code
static final int[] extra_dbits={
0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13
};
 
// extra bits for each bit length code
static final int[] extra_blbits={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7
};
 
static final byte[] bl_order={
16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
 
 
// The lengths of the bit length codes are sent in order of decreasing
// probability, to avoid transmitting the lengths for unused bit
// length codes.
 
static final int Buf_size=8*2;
 
// see definition of array dist_code below
static final int DIST_CODE_LEN=512;
 
static final byte[] _dist_code = {
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
};
 
static final byte[] _length_code={
0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
};
 
static final int[] base_length = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
64, 80, 96, 112, 128, 160, 192, 224, 0
};
 
static final int[] base_dist = {
0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
};
 
// Mapping from a distance to a distance code. dist is the distance - 1 and
// must not have side effects. _dist_code[256] and _dist_code[257] are never
// used.
static int d_code(int dist){
return ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>>7)]);
}
 
short[] dyn_tree; // the dynamic tree
int max_code; // largest code with non zero frequency
StaticTree stat_desc; // the corresponding static tree
 
// Compute the optimal bit lengths for a tree and update the total bit length
// for the current block.
// IN assertion: the fields freq and dad are set, heap[heap_max] and
// above are the tree nodes sorted by increasing frequency.
// OUT assertions: the field len is set to the optimal bit length, the
// array bl_count contains the frequencies for each bit length.
// The length opt_len is updated; static_len is also updated if stree is
// not null.
void gen_bitlen(Deflate s){
short[] tree = dyn_tree;
short[] stree = stat_desc.static_tree;
int[] extra = stat_desc.extra_bits;
int base = stat_desc.extra_base;
int max_length = stat_desc.max_length;
int h; // heap index
int n, m; // iterate over the tree elements
int bits; // bit length
int xbits; // extra bits
short f; // frequency
int overflow = 0; // number of elements with bit length too large
 
for (bits = 0; bits <= MAX_BITS; bits++) s.bl_count[bits] = 0;
 
// In a first pass, compute the optimal bit lengths (which may
// overflow in the case of the bit length tree).
tree[s.heap[s.heap_max]*2+1] = 0; // root of the heap
 
for(h=s.heap_max+1; h<HEAP_SIZE; h++){
n = s.heap[h];
bits = tree[tree[n*2+1]*2+1] + 1;
if (bits > max_length){ bits = max_length; overflow++; }
tree[n*2+1] = (short)bits;
// We overwrite tree[n*2+1] which is no longer needed
 
if (n > max_code) continue; // not a leaf node
 
s.bl_count[bits]++;
xbits = 0;
if (n >= base) xbits = extra[n-base];
f = tree[n*2];
s.opt_len += f * (bits + xbits);
if (stree!=null) s.static_len += f * (stree[n*2+1] + xbits);
}
if (overflow == 0) return;
 
// This happens for example on obj2 and pic of the Calgary corpus
// Find the first bit length which could increase:
do {
bits = max_length-1;
while(s.bl_count[bits]==0) bits--;
s.bl_count[bits]--; // move one leaf down the tree
s.bl_count[bits+1]+=2; // move one overflow item as its brother
s.bl_count[max_length]--;
// The brother of the overflow item also moves one step up,
// but this does not affect bl_count[max_length]
overflow -= 2;
}
while (overflow > 0);
 
for (bits = max_length; bits != 0; bits--) {
n = s.bl_count[bits];
while (n != 0) {
m = s.heap[--h];
if (m > max_code) continue;
if (tree[m*2+1] != bits) {
s.opt_len += ((long)bits - (long)tree[m*2+1])*(long)tree[m*2];
tree[m*2+1] = (short)bits;
}
n--;
}
}
}
 
// Construct one Huffman tree and assigns the code bit strings and lengths.
// Update the total bit length for the current block.
// IN assertion: the field freq is set for all tree elements.
// OUT assertions: the fields len and code are set to the optimal bit length
// and corresponding code. The length opt_len is updated; static_len is
// also updated if stree is not null. The field max_code is set.
void build_tree(Deflate s){
short[] tree=dyn_tree;
short[] stree=stat_desc.static_tree;
int elems=stat_desc.elems;
int n, m; // iterate over heap elements
int max_code=-1; // largest code with non zero frequency
int node; // new node being created
 
// Construct the initial heap, with least frequent element in
// heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
// heap[0] is not used.
s.heap_len = 0;
s.heap_max = HEAP_SIZE;
 
for(n=0; n<elems; n++) {
if(tree[n*2] != 0) {
s.heap[++s.heap_len] = max_code = n;
s.depth[n] = 0;
}
else{
tree[n*2+1] = 0;
}
}
 
// The pkzip format requires that at least one distance code exists,
// and that at least one bit should be sent even if there is only one
// possible code. So to avoid special checks later on we force at least
// two codes of non zero frequency.
while (s.heap_len < 2) {
node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
tree[node*2] = 1;
s.depth[node] = 0;
s.opt_len--; if (stree!=null) s.static_len -= stree[node*2+1];
// node is 0 or 1 so it does not have extra bits
}
this.max_code = max_code;
 
// The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
// establish sub-heaps of increasing lengths:
 
for(n=s.heap_len/2;n>=1; n--)
s.pqdownheap(tree, n);
 
// Construct the Huffman tree by repeatedly combining the least two
// frequent nodes.
 
node=elems; // next internal node of the tree
do{
// n = node of least frequency
n=s.heap[1];
s.heap[1]=s.heap[s.heap_len--];
s.pqdownheap(tree, 1);
m=s.heap[1]; // m = node of next least frequency
 
s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
s.heap[--s.heap_max] = m;
 
// Create a new node father of n and m
tree[node*2] = (short)(tree[n*2] + tree[m*2]);
s.depth[node] = (byte)(Math.max(s.depth[n],s.depth[m])+1);
tree[n*2+1] = tree[m*2+1] = (short)node;
 
// and insert the new node in the heap
s.heap[1] = node++;
s.pqdownheap(tree, 1);
}
while(s.heap_len>=2);
 
s.heap[--s.heap_max] = s.heap[1];
 
// At this point, the fields freq and dad are set. We can now
// generate the bit lengths.
 
gen_bitlen(s);
 
// The field len is now set, we can generate the bit codes
gen_codes(tree, max_code, s.bl_count);
}
 
// Generate the codes for a given tree and bit counts (which need not be
// optimal).
// IN assertion: the array bl_count contains the bit length statistics for
// the given tree and the field len is set for all tree elements.
// OUT assertion: the field code is set for all tree elements of non
// zero code length.
static void gen_codes(short[] tree, // the tree to decorate
int max_code, // largest code with non zero frequency
short[] bl_count // number of codes at each bit length
){
short[] next_code=new short[MAX_BITS+1]; // next code value for each bit length
short code = 0; // running code value
int bits; // bit index
int n; // code index
 
// The distribution counts are first used to generate the code values
// without bit reversal.
for (bits = 1; bits <= MAX_BITS; bits++) {
next_code[bits] = code = (short)((code + bl_count[bits-1]) << 1);
}
 
// Check that the bit counts in bl_count are consistent. The last code
// must be all ones.
//Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
// "inconsistent bit counts");
//Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
 
for (n = 0; n <= max_code; n++) {
int len = tree[n*2+1];
if (len == 0) continue;
// Now reverse the bits
tree[n*2] = (short)(bi_reverse(next_code[len]++, len));
}
}
 
// Reverse the first len bits of a code, using straightforward code (a faster
// method would use a table)
// IN assertion: 1 <= len <= 15
static int bi_reverse(int code, // the value to invert
int len // its bit length
){
int res = 0;
do{
res|=code&1;
code>>>=1;
res<<=1;
}
while(--len>0);
return res>>>1;
}
}
 
/trunk/OpenConcerto/src/org/openconcerto/map/ui/ITextComboVilleViewer.java
14,6 → 14,7
package org.openconcerto.map.ui;
 
import org.openconcerto.map.model.Ville;
import org.openconcerto.ui.PopupMouseListener;
import org.openconcerto.ui.component.ComboLockedMode;
import org.openconcerto.ui.component.ITextSelector;
import org.openconcerto.ui.component.text.DocumentComponent;
25,13 → 26,12
import org.openconcerto.utils.checks.EmptyObject;
import org.openconcerto.utils.checks.EmptyObjectHelper;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
142,29 → 142,11
});
popupMenu.add(menuItem);
 
this.text.getTextComp().addMouseListener(new MouseAdapter() {
private void maybeShowPopup(final MouseEvent e) {
this.text.getTextComp().addMouseListener(new PopupMouseListener(popupMenu));
 
if (e.isPopupTrigger()) {
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
 
@Override
public void mousePressed(final MouseEvent e) {
this.maybeShowPopup(e);
}
 
@Override
public void mouseReleased(final MouseEvent e) {
this.maybeShowPopup(e);
}
 
});
 
}
 
@Override
public void addEmptyListener(final EmptyListener l) {
this.emptyHelper.addListener(l);
}
203,10 → 185,6
return this.getValue();
}
 
public String getValidationText() {
return this.getValue() + " n'existe pas";
}
 
// *** text
 
public String getValue() {
218,13 → 196,16
return this.emptyHelper.isEmpty();
}
 
public boolean isValidated() {
@Override
public ValidState getValidState() {
final Ville villeFromVilleEtCode = Ville.getVilleFromVilleEtCode(this.getValue());
final boolean b = villeFromVilleEtCode != null;
if (b) {
this.cache.setLastGood(villeFromVilleEtCode);
return ValidState.getTrueInstance();
} else {
return new ValidState(b, this.getValue() + " n'existe pas");
}
return b;
}
 
public void resetValue() {
/trunk/OpenConcerto/src/org/openconcerto/openoffice/LengthUnit.java
81,6 → 81,10
}
}
 
public final String format(final BigDecimal d) {
return d.toPlainString() + getSymbol();
}
 
public static final LengthUnit fromSymbol(final String s) {
for (final LengthUnit lu : values())
if (lu.symbol.equals(s))
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/Cell.java
48,7 → 48,8
 
// from §5.12 of OpenDocument-v1.2-cs01-part2
// Error ::= '#' [A-Z0-9]+ ([!?] | ('/' ([A-Z] | ([0-9] [!?]))))
// we added an optional space before the marks to support OpenOffice/LibreOffice (at least until 3.4)
// we added an optional space before the marks to support OpenOffice/LibreOffice (at least until
// 3.4)
private static final Pattern ErrorPattern = Pattern.compile("#[A-Z0-9]+( ?[!?]|(/([A-Z]|([0-9] ?[!?]))))");
 
/**
232,9 → 233,13
}
 
public boolean isValid() {
return !this.getElement().getName().equals("covered-table-cell");
return !this.isCovered();
}
 
protected final boolean isCovered() {
return this.getElement().getName().equals("covered-table-cell");
}
 
public final boolean isEmpty() {
return this.getValueType() == null && this.getElement().getContentSize() == 0;
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/SpreadSheet.java
23,7 → 23,9
import org.openconcerto.openoffice.XMLFormatVersion;
import org.openconcerto.openoffice.XMLVersion;
import org.openconcerto.openoffice.spreadsheet.SheetTableModel.MutableTableModel;
import org.openconcerto.utils.Tuple2;
 
import java.awt.Point;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
133,14 → 135,34
// \1 is sheet name, \4 cell address, \6 second sheet name, \9 second cell address
static final Pattern cellRangePattern = java.util.regex.Pattern.compile("(\\$?([^\\. ']+|'([^']|'')+'))?\\.(\\$?[A-Z]+\\$?[0-9]+)(:(\\$?([^\\. ']+|'([^']|'')+'))?\\.(\\$?[A-Z]+\\$?[0-9]+))?");
 
// see 9.2.1 of OpenDocument-v1.2-cs01-part1
static final Pattern tableNameQuoteQuotePattern = Pattern.compile("''", Pattern.LITERAL);
static final Pattern tableNameQuotePattern = Pattern.compile("'", Pattern.LITERAL);
static final Pattern tableNameQuoteNeededPattern = Pattern.compile("[ \t.']");
 
static protected final String parseSheetName(final String n) {
if (n == null)
return null;
 
// ToDo handle '' (but OpenOffice doesn't)
return n.charAt(0) == '$' ? n.substring(1) : n;
String res = n.charAt(0) == '$' ? n.substring(1) : n;
if (res.charAt(0) == '\'') {
if (res.charAt(res.length() - 1) != '\'')
throw new IllegalArgumentException("Missing closing quote");
res = tableNameQuoteQuotePattern.matcher(res.substring(1, res.length() - 1)).replaceAll(tableNameQuotePattern.pattern());
}
return res;
}
 
static protected final String formatSheetName(final String n) {
if (n == null)
return null;
if (tableNameQuoteNeededPattern.matcher(n).find()) {
return "'" + tableNameQuotePattern.matcher(n).replaceAll(tableNameQuoteQuotePattern.pattern()) + "'";
} else {
return n;
}
}
 
/**
* Return a view of the passed range.
*
175,6 → 197,18
* @return the cell at the passed address.
*/
public final Cell<SpreadSheet> getCellAt(String ref) {
final Tuple2<Sheet, Point> res = this.resolve(ref);
return res.get0().getCellAt(res.get1());
}
 
/**
* Resolve a cell address.
*
* @param ref an OpenDocument cell address (see 9.2.1 of OpenDocument-v1.2-cs01-part1), e.g.
* "table.B2".
* @return the table and the cell coordinates.
*/
public final Tuple2<Sheet, Point> resolve(String ref) {
final Matcher m = cellPattern.matcher(ref);
if (!m.matches())
throw new IllegalArgumentException(ref + " is not a valid cell address: " + m.pattern().pattern());
181,7 → 215,7
final String sheetName = parseSheetName(m.group(1));
if (sheetName == null)
throw new IllegalArgumentException("no sheet specified: " + ref);
return this.getSheet(sheetName, true).getCellAt(Sheet.resolve(m.group(5), m.group(6)));
return Tuple2.create(this.getSheet(sheetName, true), Sheet.resolve(m.group(5), m.group(6)));
}
 
public XPath getXPath(String p) throws JDOMException {
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/Table.java
13,6 → 13,7
package org.openconcerto.openoffice.spreadsheet;
 
import org.openconcerto.openoffice.LengthUnit;
import org.openconcerto.openoffice.ODDocument;
import org.openconcerto.openoffice.Style;
import org.openconcerto.openoffice.StyleStyleDesc;
21,15 → 22,18
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.xml.JDOMUtils;
import org.openconcerto.xml.SimpleXMLPath;
 
import java.awt.Point;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import javax.swing.table.TableModel;
 
178,8 → 182,6
this.duplicateRows(rowDuplicated, 1, nbDuplicate);
}
 
private static Pattern regexp = Pattern.compile("((^.*)\\.(\\D*))((\\d*)$)");
 
/**
* Clone a range of rows. Eg if you want to copy once rows 2 through 5, you call
* <code>duplicateRows(2, 4, 1)</code>.
188,74 → 190,138
* @param count the number of rows after <code>start</code> to clone.
* @param copies the number of copies of the range to make.
*/
public final synchronized void duplicateRows(int start, int count, int copies) {
this.duplicateRows(start, count, copies, true);
}
 
public final synchronized void duplicateRows(int start, int count, int copies) {
public final synchronized void duplicateRows(int start, int count, int copies, boolean updateCellAddresses) {
final int stop = start + count;
// should not change merged status
final Map<Point, Integer> coverOrigins = new HashMap<Point, Integer>();
final List<Point> coverOriginsToUpdate = new ArrayList<Point>();
final int colCount = this.getColumnCount();
for (int x = 0; x < colCount;) {
int y = start;
while (y < stop) {
final Point coverOrigin = this.getCoverOrigin(x, y);
if (coverOrigin == null) {
y++;
} else {
final int lastCoveredCellRow;
// if we have already encountered this merged cell, skip it
if (coverOrigins.containsKey(coverOrigin)) {
lastCoveredCellRow = coverOrigins.get(coverOrigin);
} else {
final Cell<D> covering = this.getImmutableCellAt(coverOrigin.x, coverOrigin.y);
lastCoveredCellRow = coverOrigin.y + covering.getRowsSpanned() - 1;
if (coverOrigin.y < start) {
if (lastCoveredCellRow < stop - 1)
throw new IllegalArgumentException("Span starts before the duplicated rows and doesn't extend past the end of duplicated rows at " + getAddress(coverOrigin));
} else {
if (lastCoveredCellRow > stop - 1)
throw new IllegalArgumentException("Span starts in the duplicated rows and extend past the end of duplicated rows at " + getAddress(coverOrigin));
}
 
coverOrigins.put(coverOrigin, lastCoveredCellRow);
// merged cells inside the duplicated rows don't need to be updated
if (coverOrigin.y < start || lastCoveredCellRow > stop - 1)
coverOriginsToUpdate.add(coverOrigin);
}
y = lastCoveredCellRow + 1;
}
}
x++;
}
 
// clone xml elements and add them to our tree
final List<Element> clones = new ArrayList<Element>(count * copies);
for (int i = 0; i < copies; i++) {
for (int l = start; l < stop; l++) {
final Element r = this.rows.get(l).getElement();
Element c = (Element) r.clone();
List<Element> children = (List<Element>) c.getChildren("table-cell", c.getNamespace());
for (Element element : children) {
System.err.println("--------get table cell");
List<Element> lChild = (List<Element>) element.getChildren("frame", element.getNamespace("frame"));
for (Element element2 : lChild) {
System.err.println("---------get frame");
Attribute attribute = element2.getAttribute("end-cell-address", c.getNamespace());
final String value = attribute.getValue();
System.err.println(value);
final Matcher matcher = regexp.matcher(value);
if (matcher.matches() && matcher.groupCount() == 5) {
String result = matcher.group(1);
int val = Integer.parseInt(matcher.group(4));
val = val + (count * (i + 1));
result += val;
 
attribute.setValue(result);
System.err.println(attribute.getValue());
clones.add((Element) r.clone());
}
}
}
clones.add(c);
}
}
// works anywhere its XML element is
JDOMUtils.insertAfter(this.rows.get(stop - 1).getElement(), clones);
 
for (final Point coverOrigin : coverOriginsToUpdate) {
final MutableCell<D> coveringCell = getCellAt(coverOrigin);
coveringCell.setRowsSpanned(coveringCell.getRowsSpanned() + count * copies);
}
 
// synchronize our rows with our new tree
this.readRows();
 
// Fix image if after
for (int i = (start + (count * (copies + 1))); i < this.rows.size(); i++) {
final Element r = this.rows.get(i).getElement();
// 19.627 in OpenDocument-v1.2-cs01-part1 : The table:end-cell-address attribute specifies
// end position of the shape if it is included in a spreadsheet document.
if (updateCellAddresses && getODDocument() instanceof SpreadSheet) {
final SpreadSheet ssheet = (SpreadSheet) getODDocument();
final SimpleXMLPath<Attribute> descAttrs = SimpleXMLPath.allAttributes("end-cell-address", "table");
for (final Attribute endCellAttr : descAttrs.selectNodes(getElement())) {
final Tuple2<Sheet, Point> resolved = ssheet.resolve(endCellAttr.getValue());
final Sheet endCellSheet = resolved.get0();
if (endCellSheet != this)
throw new UnsupportedOperationException("End sheet is not this : " + endCellSheet);
final Point endCellPoint = resolved.get1();
// if the end point is before the copied rows, nothing to do
if (endCellPoint.y >= start) {
final Element endCellParentElem = endCellAttr.getParent();
 
List<Element> children = (List<Element>) r.getChildren("table-cell", r.getNamespace());
for (Element element : children) {
System.err.println("--------get table cell");
List<Element> lChild = (List<Element>) element.getChildren("frame", element.getNamespace("frame"));
for (Element element2 : lChild) {
System.err.println("---------get frame");
Attribute attribute = element2.getAttribute("end-cell-address", r.getNamespace());
final String value = attribute.getValue();
System.err.println(value);
final Matcher matcher = regexp.matcher(value);
if (matcher.matches() && matcher.groupCount() == 5) {
String result = matcher.group(1);
int val = Integer.parseInt(matcher.group(4));
val = val + (count * copies);
result += val;
// find row index of the shape
final Element rowElem = JDOMUtils.getAncestor(endCellParentElem, "table-row", getTABLE());
if (rowElem == null)
throw new IllegalStateException("Not in a row : " + JDOMUtils.output(endCellParentElem));
int startRowIndex = -1;
final int rowCount = getRowCount();
for (int i = 0; i < rowCount; i++) {
if (getRow(i).getElement() == rowElem) {
startRowIndex = i;
break;
}
}
if (startRowIndex < 0)
throw new IllegalStateException("Row not found for " + JDOMUtils.output(endCellParentElem));
final int newEndY;
if (startRowIndex >= start + (copies + 1) * count) {
// if the shape doesn't span over the copied rows, only need to offset
// end-cell-address
newEndY = endCellPoint.y + copies * count;
} else if (startRowIndex >= start + count && endCellPoint.y < start + count) {
// if the shape was copied and its end cell too, translate it
// find in which copy the shape is in, ATTN the truncation is important
// since the shape might not be in the first copied row
final int nth = (startRowIndex - start) / count;
newEndY = endCellPoint.y + nth * count;
} else {
// we must use height to compute new values for end-cell-address and end-y
 
attribute.setValue(result);
System.err.println(attribute.getValue());
// find the height of the shape
final LengthUnit unit = LengthUnit.MM;
final BigDecimal[] coordinates = getODDocument().getFormatVersion().getXML().getCoordinates(endCellParentElem, unit, false, true);
if (coordinates == null)
throw new IllegalStateException("Couldn't find the height of the shape : " + JDOMUtils.output(endCellParentElem));
final BigDecimal endYFromAnchor = coordinates[3];
assert endYFromAnchor != null : "getCoordinates() should never return null BigDecimal (unless requested by horizontal/vertical)";
// find the end row
int rowIndex = startRowIndex;
BigDecimal cellEndYFromAnchor = getRow(rowIndex).getStyle().getTableRowProperties().getHeight(unit);
while (endYFromAnchor.compareTo(cellEndYFromAnchor) > 0) {
rowIndex++;
cellEndYFromAnchor = cellEndYFromAnchor.add(getRow(rowIndex).getStyle().getTableRowProperties().getHeight(unit));
}
// find the end-y
final BigDecimal cellStartYFromAnchor = cellEndYFromAnchor.subtract(getRow(rowIndex).getStyle().getTableRowProperties().getHeight(unit));
final BigDecimal endY = endYFromAnchor.subtract(cellStartYFromAnchor);
assert endY.signum() >= 0;
 
newEndY = rowIndex;
endCellParentElem.setAttribute("end-y", unit.format(endY), getTABLE());
}
endCellAttr.setValue(SpreadSheet.formatSheetName(endCellSheet.getName()) + "." + Table.getAddress(new Point(endCellPoint.x, newEndY)));
}
}
// synchronize our rows with our new tree
this.readRows();
}
}
 
private synchronized void addRow(Element child) {
this.rows.add(new Row<D>(this, child, this.rows.size()));
319,6 → 385,49
}
 
/**
* Return the origin of a merged cell.
*
* @param x the column.
* @param y the row.
* @return the point of origin, <code>null</code> if there's no merged cell at the passed
* coordinates.
*/
public final Point getCoverOrigin(final int x, final int y) {
// can't return a Cell, since it has no x
// don't return a MutableCell since it is costly
 
final Cell<D> c = this.getImmutableCellAt(x, y);
if (c.coversOtherCells()) {
return new Point(x, y);
} else if (!c.isCovered()) {
return null;
} else {
final Row<D> row = this.getRow(y);
Cell<D> currentCell = c;
int currentX = x;
while (currentX > 0 && currentCell.isCovered()) {
currentX--;
currentCell = row.getCellAt(currentX);
}
if (currentCell.coversOtherCells())
return new Point(currentX, y);
 
if (!currentCell.isCovered()) {
currentX++;
currentCell = row.getCellAt(currentX);
}
assert currentCell.isCovered();
 
int currentY = y;
while (!currentCell.coversOtherCells()) {
currentY--;
currentCell = this.getImmutableCellAt(currentX, currentY);
}
return new Point(currentX, currentY);
}
}
 
/**
* @param row la ligne (0 a lineCount-1)
* @param column la colonnee (0 a colonneCount-1)
* @return la valeur de la cellule spécifiée.
/trunk/OpenConcerto/src/org/openconcerto/openoffice/spreadsheet/MutableCell.java
26,6 → 26,7
 
import java.awt.Color;
import java.awt.Image;
import java.awt.Point;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
88,6 → 89,17
return this.getRow().getY();
}
 
public final Point getPoint() {
return new Point(getX(), getY());
}
 
final void setRowsSpanned(final int rowsSpanned) {
if (rowsSpanned <= 1)
this.getElement().removeAttribute("number-rows-spanned", getNS().getTABLE());
else
this.getElement().setAttribute("number-rows-spanned", String.valueOf(rowsSpanned), getNS().getTABLE());
}
 
// *** setValue
 
private void setValueAttributes(ODValueType type, Object val) {
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODMeta.java
13,7 → 13,6
package org.openconcerto.openoffice;
 
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
268,17 → 267,13
return null;
else {
final Calendar cal = Calendar.getInstance();
try {
cal.setTime((Date) OOUtils.DATE_FORMAT.parseObject(date));
} catch (ParseException e) {
throw new IllegalStateException("wrong date: " + date, e);
}
cal.setTime((Date) ODValueType.DATE.parse(date));
return cal;
}
}
 
private final void setDateChild(final Calendar cal, final String name, final Namespace ns) {
this.getChild(name, ns).setText(OOUtils.DATE_FORMAT.format(cal.getTime()));
this.getChild(name, ns).setText(ODValueType.DATE.format(cal.getTime()));
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/DateStyle.java
46,8 → 46,9
}
};
 
private static final boolean isShort(final Element elem) {
return "short".equals(elem.getAttributeValue("style", elem.getNamespace("number")));
static final boolean isShort(final Element elem) {
// in OOo the default is short
return !"long".equals(elem.getAttributeValue("style", elem.getNamespace("number")));
}
 
public static final Locale getLocale(final Element elem) {
89,6 → 90,21
return res;
}
 
static String formatSecondFraction(final Locale styleLocale, final BigDecimal seconds, final int decPlaces) {
if (decPlaces > 0) {
final DecimalFormat decFormat = new DecimalFormat();
decFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(styleLocale));
decFormat.setMinimumIntegerDigits(0);
decFormat.setMaximumIntegerDigits(0);
decFormat.setMinimumFractionDigits(decPlaces);
decFormat.setMaximumFractionDigits(decPlaces);
// .12 or .578
return decFormat.format(seconds);
} else {
return "";
}
}
 
public DateStyle(final ODPackage pkg, Element elem) {
super(pkg, elem, Date.class);
}
160,15 → 176,9
// use styleLocale since <seconds> hasn't @calendar
final Calendar cal = Calendar.getInstance(styleLocale);
cal.setTime(d);
final DecimalFormat decFormat = new DecimalFormat();
decFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(styleLocale));
decFormat.setMinimumIntegerDigits(0);
decFormat.setMinimumFractionDigits(decPlaces);
decFormat.setMaximumFractionDigits(decPlaces);
final BigDecimal secondFractions = new BigDecimal(cal.get(Calendar.MILLISECOND)).movePointLeft(3);
assert secondFractions.compareTo(BigDecimal.ONE) < 0;
// .12 or .578
final String fractionPart = decFormat.format(secondFractions);
final String fractionPart = formatSecondFraction(styleLocale, secondFractions, decPlaces);
DataStyle.addStringLiteral(sb, fractionPart);
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/style/data/TimeStyle.java
14,12 → 14,20
package org.openconcerto.openoffice.style.data;
 
import org.openconcerto.openoffice.ODPackage;
import org.openconcerto.openoffice.StyleProperties;
import org.openconcerto.openoffice.XMLVersion;
import org.openconcerto.openoffice.spreadsheet.CellStyle;
 
import java.math.BigDecimal;
import java.text.DateFormatSymbols;
import java.util.List;
import java.util.Locale;
 
import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.Duration;
 
import org.jdom.Element;
import org.jdom.Namespace;
 
// from section 16.27.18 in v1.2-cs01-part1
public class TimeStyle extends DataStyle {
31,6 → 39,14
}
};
 
private static final int DAY_LENGTH_IN_HOURS = 24;
private static final int AM_LENGTH = DAY_LENGTH_IN_HOURS / 2;
 
private static final String formatInt(int i, Element elem) {
final String res = String.valueOf(i);
return !DateStyle.isShort(elem) && res.length() < 2 ? '0' + res : res;
}
 
public TimeStyle(final ODPackage pkg, Element elem) {
super(pkg, elem, Duration.class);
}
37,7 → 53,53
 
@Override
public String format(Object o, CellStyle defaultStyle, boolean lenient) {
// TODO time
throw new UnsupportedOperationException(DESC.getElementName() + " unsupported");
final Duration d = (Duration) o;
final Namespace numberNS = this.getElement().getNamespace();
final StringBuilder sb = new StringBuilder();
 
final Locale styleLocale = DateStyle.getLocale(getElement());
final boolean truncate = StyleProperties.parseBoolean(getElement().getAttributeValue("truncate-on-overflow", numberNS), true);
@SuppressWarnings("unchecked")
final List<Element> children = this.getElement().getChildren();
for (final Element elem : children) {
if (elem.getNamespace().equals(numberNS)) {
if (elem.getName().equals("text")) {
sb.append(elem.getText());
} else if (elem.getName().equals("hours")) {
int hours = d.getHours();
if (truncate)
hours = hours % DAY_LENGTH_IN_HOURS;
if (elem.getChild("am-pm", numberNS) != null) {
// Duration fields are never negative
hours = d.getHours() == 0 ? AM_LENGTH : (d.getHours() - 1) % AM_LENGTH + 1;
assert hours >= 1 && hours <= AM_LENGTH;
}
sb.append(formatInt(hours, elem));
} else if (elem.getName().equals("am-pm")) {
final boolean am = d.getHours() % DAY_LENGTH_IN_HOURS < AM_LENGTH;
sb.append(new DateFormatSymbols(styleLocale).getAmPmStrings()[am ? 0 : 1]);
} else if (elem.getName().equals("minutes")) {
final int minutes;
if (truncate && getElement().getChild("hours", numberNS) == null)
minutes = d.getMinutes() % 60;
else
minutes = d.getMinutes();
sb.append(formatInt(minutes, elem));
} else if (elem.getName().equals("seconds")) {
final BigDecimal seconds = (BigDecimal) d.getField(DatatypeConstants.SECONDS);
final int secondsIntPart;
if (truncate && getElement().getChild("hours", numberNS) == null && getElement().getChild("minutes", numberNS) == null)
secondsIntPart = seconds.intValue() % 60;
else
secondsIntPart = seconds.intValue();
sb.append(formatInt(secondsIntPart, elem));
 
final int decPlaces = StyleProperties.parseInt(elem.getAttributeValue("decimal-places", numberNS), 0);
sb.append(DateStyle.formatSecondFraction(styleLocale, seconds, decPlaces));
}
}
}
 
return sb.toString();
}
}
/trunk/OpenConcerto/src/org/openconcerto/openoffice/OOXML.java
20,6 → 20,7
import org.openconcerto.xml.JDOMUtils;
import org.openconcerto.xml.Validator;
 
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
141,6 → 142,13
return content.replaceAll("\\[" + tagName + "\\]", "<text:span text:style-name=\"" + styleName + "\">").replaceAll("\\[/" + tagName + "\\]", "</text:span>");
}
 
static private final BigDecimal parseLength(final Element elem, final String attrName, final Namespace ns, LengthUnit unit) {
final String attr = elem.getAttributeValue(attrName, ns);
if (attr == null)
return null;
return LengthUnit.parsePositiveLength(attr, unit, false);
}
 
// *** instances
 
private final XMLFormatVersion version;
309,6 → 317,138
return elem;
}
 
/**
* Return the coordinates of the top-left and bottom-right of the passed shape.
*
* @param elem an XML element.
* @param unit the unit of the returned numbers.
* @return an array of 4 numbers, <code>null</code> if <code>elem</code> is not a shape, numbers
* themselves are never <code>null</code>.
*/
public final BigDecimal[] getCoordinates(Element elem, LengthUnit unit) {
return this.getCoordinates(elem, unit, true, true);
}
 
/**
* Return the coordinates of the top-left and bottom-right of the passed shape.
*
* @param elem an XML element.
* @param unit the unit of the returned numbers.
* @param horizontal <code>true</code> if the x coordinates should be computed,
* <code>false</code> meaning items 0 and 2 of the result are <code>null</code>.
* @param vertical <code>true</code> if the y coordinates should be computed, <code>false</code>
* meaning items 1 and 3 of the result are <code>null</code>.
* @return an array of 4 numbers, <code>null</code> if <code>elem</code> is not a shape, numbers
* themselves are only <code>null</code> if requested with <code>horizontal</code> or
* <code>vertical</code>.
*/
public final BigDecimal[] getCoordinates(Element elem, LengthUnit unit, final boolean horizontal, final boolean vertical) {
return getCoordinates(elem, getVersion().getNS("svg"), unit, horizontal, vertical);
}
 
static private final BigDecimal[] getCoordinates(Element elem, final Namespace svgNS, LengthUnit unit, final boolean horizontal, final boolean vertical) {
if (elem.getName().equals("g") && elem.getNamespacePrefix().equals("draw")) {
// put below if to allow null to be returned by getLocalCoordinates() if elem isn't a
// shape
if (!horizontal && !vertical)
return new BigDecimal[] { null, null, null, null };
 
// an OpenDocument group (of shapes) doesn't have any coordinates nor any width and
// height so iterate through its components to find its coordinates
BigDecimal minX = null, minY = null;
BigDecimal maxX = null, maxY = null;
for (final Object c : elem.getChildren()) {
final Element child = (Element) c;
final BigDecimal[] childCoord = getCoordinates(child, svgNS, unit, horizontal, vertical);
// e.g. <office:event-listeners>, <svg:desc>, <svg:title>
if (childCoord != null) {
{
final BigDecimal x = childCoord[0];
final BigDecimal x2 = childCoord[2];
if (x != null) {
assert x2 != null;
if (minX == null || x.compareTo(minX) < 0)
minX = x;
if (maxX == null || x2.compareTo(maxX) > 0)
maxX = x2;
}
}
{
final BigDecimal y = childCoord[1];
final BigDecimal y2 = childCoord[3];
if (y != null) {
assert y2 != null;
if (minY == null || y.compareTo(minY) < 0)
minY = y;
if (maxY == null || y2.compareTo(maxY) > 0)
maxY = y2;
}
}
}
}
// works because we check above if both horizontal and vertical are false
if (minX == null && minY == null)
throw new IllegalArgumentException("Empty group : " + JDOMUtils.output(elem));
return new BigDecimal[] { minX, minY, maxX, maxY };
} else {
return getLocalCoordinates(elem, svgNS, unit, horizontal, vertical);
}
}
 
// return null if elem isn't a shape (no x/y or no width/height)
// BigDecimal null if and only if horizontal/vertical is false
static private final BigDecimal[] getLocalCoordinates(Element elem, final Namespace svgNS, LengthUnit unit, final boolean horizontal, final boolean vertical) {
final BigDecimal x = parseLength(elem, "x", svgNS, unit);
final BigDecimal x1 = parseLength(elem, "x1", svgNS, unit);
if (x == null && x1 == null)
return null;
 
final BigDecimal y = parseLength(elem, "y", svgNS, unit);
final BigDecimal y1 = parseLength(elem, "y1", svgNS, unit);
if (y == null && y1 == null)
throw new IllegalArgumentException("Have x but missing y in " + JDOMUtils.output(elem));
 
final BigDecimal startX;
final BigDecimal endX;
if (horizontal) {
if (x == null) {
startX = x1;
endX = parseLength(elem, "x2", svgNS, unit);
} else {
startX = x;
final BigDecimal width = parseLength(elem, "width", svgNS, unit);
endX = width == null ? null : startX.add(width);
}
// return null if there's no second coordinate (it's a point)
if (endX == null)
return null;
} else {
startX = null;
endX = null;
}
 
final BigDecimal startY;
final BigDecimal endY;
if (vertical) {
if (y == null) {
startY = y1;
endY = parseLength(elem, "y2", svgNS, unit);
} else {
startY = y;
final BigDecimal height = parseLength(elem, "height", svgNS, unit);
endY = height == null ? null : startY.add(height);
}
// return null if there's no second coordinate (it's a point)
if (endY == null)
return null;
} else {
startY = null;
endY = null;
}
 
return new BigDecimal[] { startX, startY, endX, endY };
}
 
private static final class XML_OO extends OOXML {
public XML_OO() {
super(XMLFormatVersion.getOOo(), "20020501");
/trunk/OpenConcerto/src/org/openconcerto/openoffice/OOUtils.java
14,8 → 14,6
package org.openconcerto.openoffice;
 
import org.openconcerto.utils.FileUtils;
import org.openconcerto.utils.FormatGroup;
import org.openconcerto.utils.XMLDateFormat;
import org.openconcerto.xml.JDOMUtils;
 
import java.awt.Color;
22,8 → 20,6
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.text.Format;
import java.text.SimpleDateFormat;
 
import org.jdom.Document;
import org.jdom.JDOMException;
34,18 → 30,7
import org.xml.sax.InputSource;
 
public class OOUtils {
// as per 16.1 "Data Types" and 6.7.1 "Variable Value Types and Values"
// see http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#isoformats
 
// time means Duration for OpenDocument (see 6.7.1)
public static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("'PT'HH'H'mm'M'ss'S'");
static public final Format DATE_FORMAT;
static {
// first date and time so we don't loose time information on format() or parse()
// MAYBE add HH':'mm':'ss,SSS for OOo 1
DATE_FORMAT = new FormatGroup(new XMLDateFormat(), new SimpleDateFormat("yyyy-MM-dd'T'HH':'mm':'ss"), new SimpleDateFormat("yyyy-MM-dd"));
}
 
// MAYBE configurable
static private final String[] executables = { "ooffice2", "ooffice", "soffice" };
 
/trunk/OpenConcerto/src/org/openconcerto/openoffice/ODValueType.java
13,7 → 13,11
package org.openconcerto.openoffice;
 
import org.openconcerto.utils.FormatGroup;
import org.openconcerto.utils.XMLDateFormat;
 
import java.math.BigDecimal;
import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
21,6 → 25,10
import java.util.Date;
import java.util.List;
 
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
 
/**
* A type of value, as per 16.1 "Data Types" and 6.7.1 "Variable Value Types and Values"
*/
76,7 → 84,7
@Override
public String format(Object o) {
final Date d = o instanceof Calendar ? ((Calendar) o).getTime() : (Date) o;
return OOUtils.DATE_FORMAT.format(d);
return DATE_FORMAT.format(d);
}
 
@Override
85,7 → 93,7
return null;
else {
try {
return (Date) OOUtils.DATE_FORMAT.parseObject(date);
return (Date) DATE_FORMAT.parseObject(date);
} catch (ParseException e) {
throw new IllegalStateException("wrong date: " + date, e);
}
93,36 → 101,31
}
 
},
TIME("time-value", Calendar.class) {
// FIXME
TIME("time-value", Duration.class, Calendar.class) {
 
@Override
public String format(Object o) {
if (o instanceof Duration) {
return o.toString();
} else {
final Calendar cal = (Calendar) o;
// adjust the format TZ to the calendar's
// that way even you pass a non default Calendar, if you did
// myCal.set(HOUR_OF_DAY, 22), the string will have "22H"
final SimpleDateFormat fmt = (SimpleDateFormat) OOUtils.TIME_FORMAT.clone();
final SimpleDateFormat fmt = (SimpleDateFormat) TIME_FORMAT.clone();
fmt.setTimeZone(cal.getTimeZone());
return fmt.format(cal.getTime());
}
}
 
@Override
public Calendar parse(String date) {
public Duration parse(String date) {
if (date.length() == 0)
return null;
else {
// take the calendar from the format, that way if date contains "22H"
// returnedCal.get(HOUR_OF_DAY) will return 22 (even if TIME_FORMAT wasn't set to
// the default TZ)
final Calendar cal = (Calendar) OOUtils.TIME_FORMAT.getCalendar().clone();
try {
cal.setTime((Date) OOUtils.TIME_FORMAT.parseObject(date));
} catch (ParseException e) {
throw new IllegalStateException("wrong date: " + date, e);
return getTypeFactory().newDuration(date);
}
return cal;
}
}
 
},
BOOLEAN("boolean-value", Boolean.class) {
211,7 → 214,7
return BOOLEAN;
else if (o instanceof String)
return STRING;
else if (o instanceof Calendar && !((Calendar) o).isSet(Calendar.DATE))
else if (o instanceof Duration || o instanceof Calendar && !((Calendar) o).isSet(Calendar.DATE))
return TIME;
else if (DATE.canFormat(o.getClass()))
return DATE;
219,4 → 222,26
return null;
}
 
// see http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#isoformats
 
// time means Duration for OpenDocument (see 6.7.1)
static private final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("'PT'HH'H'mm'M'ss.S'S'");
static private final Format DATE_FORMAT;
static {
// first date and time so we don't loose time information on format() or parse()
// MAYBE add HH':'mm':'ss,SSS for OOo 1
DATE_FORMAT = new FormatGroup(new XMLDateFormat(), new SimpleDateFormat("yyyy-MM-dd'T'HH':'mm':'ss"), new SimpleDateFormat("yyyy-MM-dd"));
}
 
static private DatatypeFactory typeFactory = null;
 
static public final DatatypeFactory getTypeFactory() {
if (typeFactory == null)
try {
typeFactory = DatatypeFactory.newInstance();
} catch (DatatypeConfigurationException e) {
throw new IllegalStateException(e);
}
return typeFactory;
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/warning/JLabelWarning.java
24,8 → 24,13
*
*/
public class JLabelWarning extends JLabel {
 
public JLabelWarning() {
super(ImageIconWarning.getInstance());
this(null);
}
 
public JLabelWarning(final String text) {
super(text, ImageIconWarning.getInstance(), text == null ? CENTER : LEADING);
this.addMouseListener(new MouseAdapter() {
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/ui/filters/NumberFormatFilter.java
13,12 → 13,12
package org.openconcerto.ui.filters;
 
import java.text.Format;
import java.text.NumberFormat;
 
public class NumberFormatFilter extends FormatFilter {
public class NumberFormatFilter<T extends Number> extends FormatFilter<T> {
 
public NumberFormatFilter(Format f) {
super(f, Number.class);
public NumberFormatFilter(NumberFormat f, Class<T> clazz) {
super(f, clazz);
}
 
public boolean isPartialValid(String s) {
/trunk/OpenConcerto/src/org/openconcerto/ui/filters/IntFormatFilter.java
14,14 → 14,14
package org.openconcerto.ui.filters;
 
import java.text.DecimalFormat;
import java.text.Format;
import java.text.NumberFormat;
 
public class IntFormatFilter extends NumberFormatFilter {
public class IntFormatFilter extends NumberFormatFilter<Number> {
 
static public final Format intFormat = new DecimalFormat("#");
static public final NumberFormat intFormat = new DecimalFormat("#");
 
public IntFormatFilter() {
super(intFormat);
super(intFormat, Number.class);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/filters/DecimalFormatFilter.java
13,10 → 13,11
package org.openconcerto.ui.filters;
 
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
 
public class DecimalFormatFilter extends NumberFormatFilter {
public class DecimalFormatFilter extends NumberFormatFilter<BigDecimal> {
 
static public final DecimalFormat floatFormat = new DecimalFormat("0.########");
static {
23,10 → 24,11
final DecimalFormatSymbols decimalFormatSymbols = floatFormat.getDecimalFormatSymbols();
decimalFormatSymbols.setDecimalSeparator('.');
floatFormat.setDecimalFormatSymbols(decimalFormatSymbols);
floatFormat.setParseBigDecimal(true);
}
 
public DecimalFormatFilter() {
super(floatFormat);
super(floatFormat, BigDecimal.class);
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/filters/FormatFilter.java
13,7 → 13,10
package org.openconcerto.ui.filters;
 
import org.openconcerto.utils.Tuple2;
 
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.Format;
import java.text.ParsePosition;
 
23,32 → 26,43
import javax.swing.text.DocumentFilter;
 
/**
* A document filter to restrict a document to a specific format.
* A document filter to restrict a document to a specific format. Since this actually prevents
* characters to be input, it's best if the filter is light. E.g. allow to enter too long numbers
* and check them elsewhere.
*
* @param <T> type this class can format and parse
* @author Sylvain
*/
public class FormatFilter extends DocumentFilter {
public class FormatFilter<T> extends DocumentFilter {
 
/**
* Utility method to create a filter to allow only <code>clazz</code>.
* Utility method to create a filter to allow only <code>clazz</code>. Return
* <code>&lt;? super T&gt;</code> because of some {@link Format} like
* {@link DecimalFormat#parse(String, ParsePosition)}.
*
* @param clazz the type of object to retrict to.
* @param clazz the type of object to restrict to.
* @return a suitable FormatFilter.
* @throws IllegalArgumentException if no suitable filter is found.
*/
static public final FormatFilter create(Class<?> clazz) {
static public final <T> FormatFilter<? super T> create(Class<T> clazz) {
final FormatFilter<?> res;
if (clazz.equals(BigDecimal.class))
return new DecimalFormatFilter();
if (clazz.equals(Float.class) || clazz.equals(Double.class))
return new FloatFormatFilter();
res = new DecimalFormatFilter();
else if (clazz.equals(Float.class) || clazz.equals(Double.class))
res = new FloatFormatFilter();
else if (clazz.equals(Integer.class) || clazz.equals(Long.class))
return new IntFormatFilter();
res = new IntFormatFilter();
else
throw new IllegalArgumentException("no format filter for " + clazz);
 
assert res.getValueClass().isAssignableFrom(clazz);
@SuppressWarnings("unchecked")
final FormatFilter<? super T> casted = (FormatFilter<? super T>) res;
return casted;
}
 
static public final boolean isValid(Format f, String s) {
return isValid(s, f, Object.class);
return isValid(s, f, Object.class).get0();
}
 
/**
58,15 → 72,16
* @param s the string to test.
* @param f the format s must use.
* @param c the class of the object returned by f.
* @return <code>true</code> if s is valid.
* @return whether <code>s</code> is valid and if it is, its parsed value.
*/
static public final boolean isValid(String s, Format f, Class<?> c) {
static public final <T> Tuple2<Boolean, T> isValid(String s, Format f, Class<T> c) {
if (s.isEmpty())
return true;
return Tuple2.create(true, null);
 
final ParsePosition pp = new ParsePosition(0);
final Object o = f.parseObject(s, pp);
return c.isInstance(o) && pp.getIndex() == s.length();
final boolean ok = c.isInstance(o) && pp.getIndex() == s.length();
return ok ? Tuple2.create(ok, c.cast(o)) : Tuple2.create(false, (T) null);
}
 
static private final String subString(Document doc, int offset) throws BadLocationException {
74,7 → 89,7
}
 
private final Format format;
private final Class<?> c;
private final Class<T> c;
 
/**
* Create a new instance.
82,7 → 97,7
* @param f the format the document has to comply.
* @param c the class the format has to parse to.
*/
public FormatFilter(Format f, final Class<?> c) {
public FormatFilter(Format f, final Class<T> c) {
this.format = f;
this.c = c;
}
104,6 → 119,10
}
 
public final boolean isCompleteValid(String s) {
return parse(s).get0();
}
 
public final Tuple2<Boolean, T> parse(String s) {
return isValid(s, this.getFormat(), this.c);
}
 
124,6 → 143,10
return s + " n'est que partiellement valide";
}
 
public final Class<T> getValueClass() {
return this.c;
}
 
public final Format getFormat() {
return this.format;
}
135,7 → 158,7
* @param o the object to format.
* @return its string representation.
*/
public String format(Object o) {
public String format(T o) {
return this.getFormat().format(o);
}
 
/trunk/OpenConcerto/src/org/openconcerto/ui/filters/FloatFormatFilter.java
13,10 → 13,17
package org.openconcerto.ui.filters;
 
public class FloatFormatFilter extends DecimalFormatFilter {
import java.text.DecimalFormat;
 
public class FloatFormatFilter extends NumberFormatFilter<Number> {
 
static public final DecimalFormat floatFormat = (DecimalFormat) DecimalFormatFilter.floatFormat.clone();
static {
floatFormat.setParseBigDecimal(false);
}
 
public FloatFormatFilter() {
super();
super(floatFormat, Number.class);
}
 
/**
23,7 → 30,7
* Format.format() prints the exact value (eg 1.09999985) toString() prints a more human
* representation (eg 1.1) see {@link Float#toString(float)}.
*/
public String format(Object o) {
public String format(Number o) {
return o.toString();
}
 
/trunk/OpenConcerto/src/org/openconcerto/ui/JDateTime.java
15,6 → 15,7
 
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
138,8 → 139,8
}
 
@Override
public boolean isValidated() {
return true;
public ValidState getValidState() {
return ValidState.getTrueInstance();
}
 
@Override
151,9 → 152,4
public void removeValidListener(ValidListener l) {
// nothing to do
}
 
@Override
public String getValidationText() {
return null;
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/JTime.java
17,6 → 17,7
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.utils.checks.ValidChangeSupport;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.BorderLayout;
import java.beans.PropertyChangeEvent;
104,7 → 105,7
}
});
// initial value
this.validSupp = new ValidChangeSupport(this, this.text.isEditValid());
this.validSupp = new ValidChangeSupport(this, ValidState.getNoReasonInstance(this.text.isEditValid()));
 
this.resetValue();
}
175,11 → 176,11
}
 
protected final void setValidated(boolean newValue) {
this.validSupp.fireValidChange(newValue);
this.validSupp.fireValidChange(ValidState.getNoReasonInstance(newValue));
}
 
@Override
public boolean isValidated() {
public ValidState getValidState() {
return this.validSupp.getValidState();
}
 
194,11 → 195,6
}
 
@Override
public String getValidationText() {
return null;
}
 
@Override
public JTextComponent getTextComp() {
return this.getEditor();
}
/trunk/OpenConcerto/src/org/openconcerto/ui/UserExit.java
14,10 → 14,10
package org.openconcerto.ui;
 
import java.awt.Component;
import java.awt.Frame;
import java.awt.Window;
 
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
 
/**
* Utility class for asking the user to exit an application. If the answer is no, nothing happen,
27,6 → 27,19
*/
public final class UserExit {
 
static public void closeAllWindows(final Window last) {
// dispose of every window (this will call windowClosed())
for (final Window f : Window.getWindows()) {
// check isDisplayable() to avoid triggering a second HierarchyEvent with the same
// displayability which can confuse some listeners
if (f != last && f.isDisplayable())
f.dispose();
}
// this is last to exit
if (last != null)
last.dispose();
}
 
private final Component comp;
private final Runnable r;
 
38,11 → 51,8
public UserExit(final Component comp) {
this(comp, new Runnable() {
public void run() {
for (final Frame f : JFrame.getFrames()) {
if (f != null)
f.dispose();
closeAllWindows(comp == null ? null : SwingUtilities.getWindowAncestor(comp));
}
}
});
}
 
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/JavaPrefPreferencePanel.java
19,6 → 19,7
import org.openconcerto.utils.checks.ValidChangeSupport;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidObject;
import org.openconcerto.utils.checks.ValidState;
 
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
44,7 → 45,6
private final Set<PrefView<?>> views;
private boolean modified;
private final ValidChangeSupport validSupp;
private String invalidityCause;
 
public JavaPrefPreferencePanel(final String title, final Preferences prefs) {
this.title = title;
53,7 → 53,6
this.views = new HashSet<PrefView<?>>();
this.modified = false;
this.validSupp = new ValidChangeSupport(this);
this.invalidityCause = null;
}
 
public final void setPrefs(Preferences prefs) {
97,8 → 96,8
});
vw.addValidListener(new ValidListener() {
@Override
public void validChange(ValidObject src, boolean newValue) {
JavaPrefPreferencePanel.this.validSupp.fireValidChange(isValidated());
public void validChange(ValidObject src, ValidState newValue) {
JavaPrefPreferencePanel.this.validSupp.fireValidChange(getValidState());
}
});
}
158,13 → 157,14
// ValidObject
 
@Override
public final boolean isValidated() {
public ValidState getValidState() {
boolean res = true;
final List<String> pbs = new ArrayList<String>();
for (final PrefView<?> v : this.views) {
if (!v.getVW().isValidated()) {
final ValidState validState = v.getVW().getValidState();
if (!validState.isValid()) {
String explanation = "'" + v.getName() + "' n'est pas valide";
final String txt = v.getVW().getValidationText();
final String txt = validState.getValidationText();
if (txt != null)
explanation += " (" + txt + ")";
pbs.add(explanation);
171,16 → 171,10
res = false;
}
}
this.invalidityCause = res ? null : CollectionUtils.join(pbs, "\n");
return res;
return ValidState.create(res, CollectionUtils.join(pbs, "\n"));
}
 
@Override
public final String getValidationText() {
return this.invalidityCause;
}
 
@Override
public final void addValidListener(ValidListener l) {
this.validSupp.addValidListener(l);
}
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/MainPrefPanel.java
16,6 → 16,7
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidObject;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.Component;
import java.awt.Font;
61,9 → 62,9
private final JButton buttonApply = new JButton("Appliquer");
private final ValidListener validListener = new ValidListener() {
@Override
public void validChange(ValidObject src, boolean newValue) {
MainPrefPanel.this.buttonApply.setEnabled(newValue);
MainPrefPanel.this.buttonApply.setToolTipText(src.getValidationText());
public void validChange(ValidObject src, ValidState newValue) {
MainPrefPanel.this.buttonApply.setEnabled(newValue.isValid());
MainPrefPanel.this.buttonApply.setToolTipText(newValue.getValidationText());
}
};
 
245,7 → 246,7
this.currentPanel = p;
this.currentPanel.addValidListener(this.validListener);
// initial value
this.validListener.validChange(this.currentPanel, this.currentPanel.isValidated());
this.validListener.validChange(this.currentPanel, this.currentPanel.getValidState());
this.add((JComponent) this.currentPanel, c);
this.revalidate();
this.repaint();
/trunk/OpenConcerto/src/org/openconcerto/ui/preferences/DefaultPreferencePanel.java
14,6 → 14,7
package org.openconcerto.ui.preferences;
 
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.text.SimpleDocumentListener;
 
import java.awt.Component;
191,16 → 192,11
// * ValidObject
 
@Override
public boolean isValidated() {
return true;
public ValidState getValidState() {
return ValidState.getTrueInstance();
}
 
@Override
public String getValidationText() {
return null;
}
 
@Override
public void addValidListener(ValidListener l) {
// nothing to do
}
/trunk/OpenConcerto/src/org/openconcerto/ui/ISpinner.java
15,6 → 15,7
 
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
 
import java.beans.PropertyChangeListener;
 
49,18 → 50,12
}
 
@Override
public String getValidationText() {
public ValidState getValidState() {
// TODO Auto-generated method stub
return null;
return ValidState.getTrueInstance();
}
 
@Override
public boolean isValidated() {
// TODO Auto-generated method stub
return true;
}
 
@Override
public void resetValue() {
this.setValue(null);
}
/trunk/OpenConcerto/src/org/openconcerto/ui/JDate.java
16,6 → 16,7
import org.openconcerto.ui.component.text.TextComponent;
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
 
import java.beans.PropertyChangeListener;
import java.util.Calendar;
94,8 → 95,9
return this;
}
 
public boolean isValidated() {
return true;
@Override
public ValidState getValidState() {
return ValidState.getTrueInstance();
}
 
public void addValidListener(ValidListener l) {
107,10 → 109,6
// nothing to do
}
 
public String getValidationText() {
return null;
}
 
public JTextComponent getTextComp() {
return getEditor();
}
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/DummyValueWrapper.java
13,6 → 13,8
package org.openconcerto.ui.valuewrapper;
 
import org.openconcerto.utils.checks.ValidState;
 
import javax.swing.JComponent;
 
/**
30,8 → 32,9
return null;
}
 
public boolean isValidated() {
return true;
@Override
public ValidState getValidState() {
return ValidState.getTrueInstance();
}
 
public void setValue(T val) {
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/ValidatedValueWrapper.java
New file
0,0 → 1,150
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.ui.valuewrapper;
 
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.checks.ValidChangeSupport;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidObject;
import org.openconcerto.utils.checks.ValidState;
 
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.LinkedHashSet;
import java.util.Set;
 
import javax.swing.JComponent;
 
/**
* Allow to add validation to the value of a {@link ValueWrapper}.
*
* @author Sylvain CUAZ
* @param <T> the type of value.
* @see #add(ValueWrapper, ITransformer)
*/
public final class ValidatedValueWrapper<T> implements ValueWrapper<T> {
 
/**
* Adds a validation to the passed value wrapper.
*
* @param <T> the type of value.
* @param vw the value wrapper to be validated.
* @param validator will be passed the value of <code>vw</code> (only when it is itself valid).
* @return a valid wrapper performing additional validation.
*/
static public final <T> ValidatedValueWrapper<T> add(final ValueWrapper<T> vw, final ITransformer<? super T, ValidState> validator) {
if (vw instanceof ValidatedValueWrapper) {
return ((ValidatedValueWrapper<T>) vw).add(validator);
} else {
return new ValidatedValueWrapper<T>(vw, validator);
}
}
 
private final ValueWrapper<T> delegate;
private final Set<ITransformer<? super T, ValidState>> validators;
private ValidState delegateValid;
private ValidState selfValid;
private final ValidChangeSupport validSupp;
 
private ValidatedValueWrapper(final ValueWrapper<T> vw, final ITransformer<? super T, ValidState> validator) {
this.delegate = vw;
this.validators = new LinkedHashSet<ITransformer<? super T, ValidState>>();
 
this.validSupp = new ValidChangeSupport(this);
final ValidListener validL = new ValidListener() {
@Override
public void validChange(ValidObject src, ValidState newValue) {
ValidatedValueWrapper.this.delegateValid = newValue;
updateValidated();
}
};
// initialize delegateValid
validL.validChange(this.delegate, this.delegate.getValidState());
this.delegate.addValidListener(validL);
this.delegate.addValueListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
updateValidated();
}
});
this.add(validator);
}
 
public final ValidatedValueWrapper<T> add(final ITransformer<? super T, ValidState> validator) {
this.validators.add(validator);
updateValidated();
return this;
}
 
private void updateValidated() {
if (!this.delegateValid.isValid()) {
this.selfValid = this.delegateValid;
} else {
// only ask getValue() if delegate is valid, otherwise might be meaningless
final T value = this.delegate.getValue();
ValidState valid = ValidState.getTrueInstance();
for (final ITransformer<? super T, ValidState> validator : this.validators) {
valid = valid.and(validator.transformChecked(value));
}
this.selfValid = valid;
}
this.validSupp.fireValidChange(this.selfValid);
}
 
@Override
public ValidState getValidState() {
return this.validSupp.getValidState();
}
 
@Override
public void addValidListener(ValidListener l) {
this.validSupp.addValidListener(l);
}
 
@Override
public void removeValidListener(ValidListener l) {
this.validSupp.removeValidListener(l);
}
 
@Override
public void addValueListener(PropertyChangeListener l) {
this.delegate.addValueListener(l);
}
 
@Override
public void rmValueListener(PropertyChangeListener l) {
this.delegate.rmValueListener(l);
}
 
@Override
public void setValue(T val) {
this.delegate.setValue(val);
}
 
@Override
public void resetValue() {
this.delegate.resetValue();
}
 
@Override
public T getValue() {
return this.delegate.getValue();
}
 
@Override
public JComponent getComp() {
return this.delegate.getComp();
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/EmptyValueWrapper.java
18,6 → 18,7
import org.openconcerto.utils.checks.EmptyObj;
import org.openconcerto.utils.checks.EmptyObjFromVO;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
 
import java.beans.PropertyChangeListener;
 
65,14 → 66,11
return this.vw.getValue();
}
 
public boolean isValidated() {
return this.vw.isValidated();
@Override
public ValidState getValidState() {
return this.vw.getValidState();
}
 
public String getValidationText() {
return this.vw.getValidationText();
}
 
public void rmValueListener(final PropertyChangeListener l) {
this.vw.rmValueListener(l);
}
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/BooleanValueWrapper.java
13,6 → 13,8
package org.openconcerto.ui.valuewrapper;
 
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
43,8 → 45,8
this.b.setSelected(val == null ? false : val);
}
 
public boolean isValidated() {
return true;
@Override
public ValidState getValidState() {
return ValidState.getTrueInstance();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/ConvertorValueWrapper.java
14,6 → 14,7
package org.openconcerto.ui.valuewrapper;
 
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.convertor.ValueConvertor;
 
import java.beans.PropertyChangeListener;
48,14 → 49,11
this.delegate.removeValidListener(l);
}
 
public String getValidationText() {
return this.delegate.getValidationText();
@Override
public ValidState getValidState() {
return this.delegate.getValidState();
}
 
public boolean isValidated() {
return this.delegate.isValidated();
}
 
// * value
 
public void addValueListener(PropertyChangeListener l) {
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/ValueChangeSupport.java
14,6 → 14,7
package org.openconcerto.ui.valuewrapper;
 
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
 
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
36,7 → 37,7
private final PropertyChangeSupport supp;
 
private final List<ValidListener> validListeners;
private Boolean valid;
private ValidState valid;
private boolean signalInvalid;
 
public ValueChangeSupport(ValueWrapper<T> vw) {
48,10 → 49,10
}
 
public final void fireValueChange() {
final boolean newValid = this.vw.isValidated();
final ValidState newValid = this.vw.getValidState();
 
// check the validity (eg '-' for a number wrapper is an unvalid change)
if (newValid)
if (newValid.isValid())
this.supp.firePropertyChange("value", null, this.vw.getValue());
else if (this.signalInvalid)
this.supp.firePropertyChange(INVALID_VALUE, null, null);
63,10 → 64,10
* Some components do not fire a value change when becoming invalid.
*/
public final void fireValidChange() {
this.setValid(this.vw.isValidated());
this.setValid(this.vw.getValidState());
}
 
private final void setValid(final Boolean newValid) {
private final void setValid(final ValidState newValid) {
if (!newValid.equals(this.valid)) {
this.valid = newValid;
for (final ValidListener l : this.validListeners) {
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/TextValueWrapper.java
16,6 → 16,7
import org.openconcerto.ui.component.IDocument;
import org.openconcerto.ui.component.text.DocumentComponent;
import org.openconcerto.ui.component.text.TextComponentUtils;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.text.SimpleDocumentListener;
 
import javax.swing.JComponent;
66,8 → 67,9
this.doc.setText(val);
}
 
public boolean isValidated() {
return true;
@Override
public ValidState getValidState() {
return ValidState.getTrueInstance();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/JFormattedTextFieldValueWrapper.java
13,6 → 13,8
package org.openconcerto.ui.valuewrapper;
 
import org.openconcerto.utils.checks.ValidState;
 
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
 
63,8 → 65,8
}
 
@Override
public boolean isValidated() {
return this.tf.isEditValid();
public ValidState getValidState() {
return ValidState.getNoReasonInstance(this.tf.isEditValid());
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/ValueWrapperFromVO.java
16,6 → 16,7
import org.openconcerto.utils.checks.MutableValueObject;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidObject;
import org.openconcerto.utils.checks.ValidState;
 
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
46,7 → 47,7
});
if (this.hasValidObject())
this.getValidObject().addValidListener(new ValidListener() {
public void validChange(ValidObject src, boolean newValue) {
public void validChange(ValidObject src, ValidState newValue) {
firePropertyChange();
}
});
72,19 → 73,12
this.vo.setValue(val);
}
 
public boolean isValidated() {
if (hasValidObject())
return this.getValidObject().isValidated();
else
return true;
}
 
@Override
public String getValidationText() {
public ValidState getValidState() {
if (hasValidObject())
return this.getValidObject().getValidationText();
return this.getValidObject().getValidState();
else
return super.getValidationText();
return ValidState.getTrueInstance();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/BaseValueWrapper.java
52,10 → 52,6
this.supp.removeValidListener(l);
}
 
public String getValidationText() {
return null;
}
 
public void resetValue() {
this.setValue(null);
}
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/format/VWFormatValueWrapper.java
24,13 → 24,15
private final ValueWrapper<String> vw;
 
public VWFormatValueWrapper(final ValueWrapper<String> b, final Class<T> c) {
super(b.getComp(), FormatFilter.create(c));
super(b.getComp(), FormatFilter.create(c), c);
this.vw = b;
this.vw.addValueListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange();
textChanged();
}
});
// initial values
this.textChanged();
}
 
protected String getText() {
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/format/FormatValueWrapper.java
17,18 → 17,18
import org.openconcerto.ui.filters.FormatFilter;
import org.openconcerto.ui.valuewrapper.BaseValueWrapper;
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.utils.ExceptionUtils;
import org.openconcerto.utils.CompareUtils;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.checks.ValidChangeSupport;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidObject;
import org.openconcerto.utils.checks.ValidObjectCombiner;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.convertor.NumberConvertor.OverflowException;
import org.openconcerto.utils.convertor.NumberConvertor.RoundingException;
import org.openconcerto.utils.convertor.ValueConvertor;
import org.openconcerto.utils.convertor.ValueConvertorFactory;
 
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.Format;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
 
import javax.swing.JComponent;
import javax.swing.text.AbstractDocument;
import javax.swing.text.Document;
57,83 → 57,130
return text == null || text.length() == 0;
}
 
private final JComponent comp;
private final FormatFilter formatFilter;
// class only needed to please Java (captures F)
private static class FilterAndConvertor<F, T extends F> {
public static <U, T extends U> FilterAndConvertor<U, T> create(final FormatFilter<U> formatFilter, final Class<T> clazz) {
return new FilterAndConvertor<U, T>(formatFilter, clazz);
}
 
private final ValidObjectCombiner comb;
private final Class<T> valueClass;
private final FormatFilter<F> formatFilter;
private final ValueConvertor<F, T> convertor;
 
protected FormatValueWrapper(final JComponent b, final FormatFilter f) {
this.comp = b;
this.formatFilter = f;
public FilterAndConvertor(final FormatFilter<F> formatFilter, final Class<T> clazz) {
this.valueClass = clazz;
this.formatFilter = formatFilter;
this.convertor = ValueConvertorFactory.find(formatFilter.getValueClass(), clazz);
if (this.convertor == null)
throw new IllegalArgumentException("No convertor found between " + clazz + " and " + formatFilter.getValueClass());
}
 
// this validObject is the combination of comp & this format
this.comb = ValidObjectCombiner.create(this, this.comp, new ValidObject() {
public final Class<T> getValueClass() {
return this.valueClass;
}
 
private final List<ValidListener> listeners = new ArrayList<ValidListener>();
public final FormatFilter<F> getFormatFilter() {
return this.formatFilter;
}
 
{
// isValidated() depends on getText(), ie the value
FormatValueWrapper.this.addValueListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
fireValidChange();
public final Tuple2<ValidState, T> parseText(final String text) {
ValidState newState;
T newValue;
if (isNull(text)) {
newState = ValidState.getTrueInstance();
newValue = null;
} else {
final Tuple2<Boolean, F> res = this.getFormatFilter().parse(text);
if (!res.get0()) {
newState = ValidState.create(false, this.getFormatFilter().getValidationText(text));
newValue = null;
} else {
try {
newValue = this.convertor.convert(res.get1());
newState = ValidState.getTrueInstance();
} catch (Exception e) {
final String msg;
if (e instanceof OverflowException)
msg = "Nombre trop grand";
else if (e instanceof RoundingException)
msg = "Entier attendu";
else if (e instanceof ClassCastException)
msg = "Mauvais type, attendu " + this.getValueClass();
else {
e.printStackTrace();
msg = e.getLocalizedMessage();
}
});
newValue = null;
newState = ValidState.create(false, msg);
}
 
private void fireValidChange() {
for (final ValidListener l : this.listeners)
l.validChange(this, this.isValidated());
}
}
return Tuple2.create(newState, newValue);
}
}
 
private final JComponent comp;
private final FilterAndConvertor<? super T, T> formatFilter;
 
private final ValidChangeSupport selfValidSupp;
private final ValidObjectCombiner comb;
private T value;
 
protected FormatValueWrapper(final JComponent b, final FormatFilter<? super T> f, final Class<T> clazz) {
this.comp = b;
this.formatFilter = FilterAndConvertor.create(f, clazz);
 
// this validObject is the combination of comp & this format
final ValidChangeSupport validSupp = new ValidChangeSupport(this);
this.selfValidSupp = validSupp;
this.comb = ValidObjectCombiner.create(this, this.comp, new ValidObject() {
@Override
public void addValidListener(final ValidListener l) {
this.listeners.add(l);
validSupp.addValidListener(l);
}
 
@Override
public void removeValidListener(ValidListener l) {
this.listeners.remove(l);
validSupp.removeValidListener(l);
}
 
public String getValidationText() {
return f.getValidationText(getText());
@Override
public ValidState getValidState() {
return validSupp.getValidState();
}
 
public boolean isValidated() {
return isFormatValidated();
}
});
// if any of comb objects change, we change
this.comb.addValidListener(new ValidListener() {
public void validChange(ValidObject src, boolean newValue) {
firePropertyChange();
public void validChange(ValidObject src, ValidState newValue) {
FormatValueWrapper.this.supp.fireValidChange();
}
});
// ATTN must call textChanged() but subclass might not yet be initialized
}
 
protected final void textChanged() {
final Tuple2<ValidState, T> newState = this.formatFilter.parseText(getText());
this.selfValidSupp.fireValidChange(newState.get0());
this.setSelfValue(newState.get1());
}
 
private final void setSelfValue(T val) {
if (!CompareUtils.equals(this.value, val)) {
this.value = val;
this.supp.fireValueChange();
}
}
 
public final JComponent getComp() {
return this.comp;
}
 
public final Format getFormat() {
return this.formatFilter.getFormat();
}
 
@SuppressWarnings("unchecked")
public final T getValue() {
final String text = this.getText();
try {
if (isNull(text) || this.formatFilter.isPartialValid(text))
return null;
else
return (T) this.getFormat().parseObject(text);
} catch (ParseException e) {
throw ExceptionUtils.createExn(IllegalStateException.class, "unable to parse " + text, e);
return this.value;
}
}
 
public final void setValue(T val) {
this.setText(val == null ? "" : this.formatFilter.format(val));
this.setText(val == null ? "" : this.formatFilter.getFormatFilter().format(val));
}
 
abstract protected String getText();
140,18 → 187,9
 
abstract protected void setText(String s);
 
public final boolean isValidated() {
return this.comb.isValidated();
}
 
private final boolean isFormatValidated() {
final String text = this.getText();
return isNull(text) || this.formatFilter.isCompleteValid(text);
}
 
@Override
public String getValidationText() {
return this.comb.getValidationText();
public ValidState getValidState() {
return this.comb.getValidState();
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/ui/valuewrapper/format/FilterFormatValueWrapper.java
17,8 → 17,8
import org.openconcerto.ui.component.text.DocumentComponent;
import org.openconcerto.ui.filters.FormatFilter;
import org.openconcerto.utils.text.DocumentFilterList;
import org.openconcerto.utils.text.DocumentFilterList.FilterType;
import org.openconcerto.utils.text.SimpleDocumentListener;
import org.openconcerto.utils.text.DocumentFilterList.FilterType;
 
import javax.swing.JComponent;
import javax.swing.event.DocumentEvent;
38,15 → 38,18
}
 
FilterFormatValueWrapper(final JComponent b, final AbstractDocument doc, final Class<T> c) {
super(b, FormatFilter.create(c));
super(b, FormatFilter.create(c), c);
this.doc = new IDocument(doc);
doc.addDocumentListener(new SimpleDocumentListener() {
public void update(DocumentEvent e) {
firePropertyChange();
textChanged();
}
});
// FormatFilter only blocks invalid input
DocumentFilterList.add(doc, FormatFilter.create(c), FilterType.SIMPLE_FILTER);
// initial values
this.textChanged();
}
 
protected String getText() {
/trunk/OpenConcerto/src/org/openconcerto/ui/table/TablePopupMouseListener.java
13,9 → 13,9
package org.openconcerto.ui.table;
 
import org.openconcerto.ui.PopupMouseListener;
import org.openconcerto.utils.cc.ITransformer;
 
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
 
27,7 → 27,7
*
* @author Sylvain
*/
public final class TablePopupMouseListener extends MouseAdapter {
public final class TablePopupMouseListener extends PopupMouseListener {
 
/**
* Add a {@link MouseListener} on <code>t</code> to select on MousePress and display a popup.
39,12 → 39,11
t.addMouseListener(new TablePopupMouseListener(popup));
}
 
private final ITransformer<MouseEvent, JPopupMenu> popup;
 
private TablePopupMouseListener(final ITransformer<MouseEvent, JPopupMenu> popup) {
this.popup = popup;
super(popup);
}
 
@Override
public void mousePressed(MouseEvent e) {
// do as other apps : select on MousePress
// BUTTON1 is already handled by Swing
51,24 → 50,15
if (e.getButton() != MouseEvent.BUTTON1) {
adjustSelection(e);
}
maybeShowPopup(e);
super.mousePressed(e);
}
 
public void mouseReleased(MouseEvent e) {
maybeShowPopup(e);
}
 
private void maybeShowPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
@Override
protected JPopupMenu createPopup(MouseEvent e) {
// select the line where the mouse is now
adjustSelection(e);
// ne pas afficher un menu vide
final JPopupMenu menu = this.popup.transformChecked(e);
if (menu != null && menu.getSubElements().length > 0) {
menu.show(e.getComponent(), e.getX(), e.getY());
return super.createPopup(e);
}
}
}
 
private void adjustSelection(final MouseEvent e) {
final JTable table = (JTable) e.getSource();
/trunk/OpenConcerto/src/org/openconcerto/ui/PopupMouseListener.java
New file
0,0 → 1,68
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.ui;
 
import org.openconcerto.utils.cc.ConstantFactory;
import org.openconcerto.utils.cc.ITransformer;
 
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
 
import javax.swing.JPopupMenu;
 
/**
* To easily add a popup.
*
* @author Sylvain
*/
public class PopupMouseListener extends MouseAdapter {
 
private final ITransformer<MouseEvent, JPopupMenu> popup;
 
public PopupMouseListener() {
this((JPopupMenu) null);
}
 
public PopupMouseListener(final JPopupMenu menu) {
this(ConstantFactory.<MouseEvent, JPopupMenu> createTransformer(menu));
}
 
public PopupMouseListener(final ITransformer<MouseEvent, JPopupMenu> popup) {
this.popup = popup;
}
 
@Override
public void mousePressed(MouseEvent e) {
maybeShowPopup(e);
}
 
@Override
public void mouseReleased(MouseEvent e) {
maybeShowPopup(e);
}
 
private void maybeShowPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
// ne pas afficher un menu vide
final JPopupMenu menu = createPopup(e);
if (menu != null && menu.getSubElements().length > 0) {
menu.show(e.getComponent(), e.getX(), e.getY());
}
}
}
 
protected JPopupMenu createPopup(MouseEvent e) {
return this.popup.transformChecked(e);
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextCombo.java
23,6 → 23,7
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.utils.CompareUtils;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.model.ListComboBoxModel;
import org.openconcerto.utils.text.DocumentFilterList;
import org.openconcerto.utils.text.SimpleDocumentFilter;
395,11 → 396,13
return this;
}
 
public boolean isValidated() {
@Override
public ValidState getValidState() {
// string toujours valide
return true;
return ValidState.getTrueInstance();
}
 
@Override
public void addValidListener(ValidListener l) {
// nothing to do
}
409,10 → 412,6
// nothing to do
}
 
public String getValidationText() {
return null;
}
 
// document
 
public JTextComponent getTextComp() {
/trunk/OpenConcerto/src/org/openconcerto/ui/component/combo/ISearchableCombo.java
28,6 → 28,7
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.model.DefaultIMutableListModel;
import org.openconcerto.utils.model.IListModel;
import org.openconcerto.utils.model.IMutableListModel;
917,6 → 918,8
this.text.add(this.getBtn());
this.updateMargin();
this.add(this.text);
// needed otherwise it grows but never shrinks
this.setMinimumSize(new Dimension(this.getMinimumSize()));
 
// listeners
this.text.getDocument().addDocumentListener(new SimpleDocumentListener() {
1065,14 → 1068,12
 
// * valid
 
public boolean isValidated() {
return this.getMode() != LOCKED || !this.invalidEdit;
@Override
public ValidState getValidState() {
final boolean res = this.getMode() != LOCKED || !this.invalidEdit;
return ValidState.createCached(res, "la valeur ne fait pas partie des choix");
}
 
public String getValidationText() {
return "la valeur ne fait pas partie des choix";
}
 
public void addValidListener(final ValidListener l) {
this.supp.addValidListener(l);
}
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextSelectorCompletionThread.java
66,12 → 66,16
// on vide le model
model.removeAllElements();
model.addAll(l);
 
if (l.size() > 1) {
combo.showCompletionPopup();
} else if (l.size() == 1) {
String str = l.get(0);
if (str.trim().equalsIgnoreCase(t.trim())) {
final String trimedText = t.trim();
final int size = l.size();
if (size > 0) {
boolean match = false;
for (int i = 0; i < size; i++) {
if (l.get(i).trim().equalsIgnoreCase(trimedText)) {
match = true;
}
}
if (match) {
combo.hideCompletionPopup();
} else {
combo.showCompletionPopup();
/trunk/OpenConcerto/src/org/openconcerto/ui/component/ITextSelector.java
25,6 → 25,7
import org.openconcerto.ui.valuewrapper.ValueChangeSupport;
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.model.ListComboBoxModel;
 
import java.awt.Color;
367,10 → 368,12
return this;
}
 
public boolean isValidated() {
return true;
@Override
public ValidState getValidState() {
return ValidState.getTrueInstance();
}
 
@Override
public void addValidListener(final ValidListener l) {
this.supp.addValidListener(l);
}
388,11 → 391,6
return this.text.getDocument();
}
 
public String getValidationText() {
// TODO Auto-generated method stub
return null;
}
 
ITextSelectorCompletionThread th = null;
 
private synchronized void updateAutoCompletion(final boolean showAll) {
/trunk/OpenConcerto/src/org/openconcerto/ui/component/MutableListComboPopupListener.java
14,17 → 14,77
package org.openconcerto.ui.component;
 
import static org.openconcerto.ui.component.ComboLockedMode.UNLOCKED;
import org.openconcerto.ui.PopupMouseListener;
import org.openconcerto.ui.SwingThreadUtils;
 
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashSet;
import java.util.Set;
 
import javax.swing.JComboBox;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
 
public class MutableListComboPopupListener extends MouseAdapter {
public class MutableListComboPopupListener {
 
static private final Set<JPopupMenu> toClose = new HashSet<JPopupMenu>();
static private final PropertyChangeListener propL = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
final JPopupMenu src = (JPopupMenu) evt.getSource();
if (!src.isVisible()) {
removePopup(src);
}
}
};
/**
* normally BasicPopupMenuUI.MouseGrabber.eventDispatched() closes popups, but BasicComboBoxUI
* sets HIDE_POPUP_KEY to indicate that it will take care of all popups, including ours, so we
* must mimic its behavior for JComboBox.
*/
static private final AWTEventListener l = new AWTEventListener() {
@Override
public void eventDispatched(AWTEvent event) {
final MouseEvent me = (MouseEvent) event;
if (me.getID() != MouseEvent.MOUSE_PRESSED && me.getID() != MouseEvent.MOUSE_WHEEL)
return;
 
final Component src = me.getComponent();
final JPopupMenu menuClicked = SwingThreadUtils.getAncestorOrSelf(JPopupMenu.class, src);
final Set<JPopupMenu> sansClicked = new HashSet<JPopupMenu>(toClose);
if (menuClicked != null)
sansClicked.remove(menuClicked);
for (JPopupMenu menu : sansClicked) {
menu.setVisible(false);
}
}
};
 
static private void addPopup(JPopupMenu p) {
// ATTN the popup might not yet be visible
if (toClose.add(p) && toClose.size() == 1) {
Toolkit.getDefaultToolkit().addAWTEventListener(l, AWTEvent.MOUSE_EVENT_MASK);
}
// if the popup is closed for any reason (programmatically, menu item chosen), we no longer
// need to handle it
p.addPropertyChangeListener("visible", propL);
}
 
static private void removePopup(JPopupMenu p) {
p.removePropertyChangeListener("visible", propL);
if (toClose.remove(p) && toClose.size() == 0) {
Toolkit.getDefaultToolkit().removeAWTEventListener(l);
}
}
 
private final MutableListCombo combo;
private JPopupMenu popup;
 
35,15 → 95,24
}
 
public void listen() {
this.combo.getPopupComp().addMouseListener(this);
this.combo.getPopupComp().addMouseListener(new PopupMouseListener() {
@Override
protected JPopupMenu createPopup(MouseEvent e) {
return getPopup(e);
}
 
public final void mouseReleased(MouseEvent ev) {
// right-click only, respect enabled status
if (ev.getButton() != MouseEvent.BUTTON3 || !this.combo.getPopupComp().isEnabled()) {
return;
});
}
 
protected final JPopupMenu getPopup(MouseEvent ev) {
// respect enabled status
if (!this.combo.getPopupComp().isEnabled())
return null;
// Bouton droit en non locked
// On debloque le lock en faisant CTRL + bouton droit
final boolean displayPopup = this.combo.getMode() == UNLOCKED || (ev.isControlDown() && this.combo.getMode() == ComboLockedMode.ITEMS_LOCKED);
if (!displayPopup)
return null;
 
if (this.popup == null) {
this.popup = new JPopupMenu();
final JMenuItem menu1 = new JMenuItem("Ajouter à la liste");
62,10 → 131,9
}
});
}
// Bouton droit en non locked
// On debloque le lock en faisant CTRL + bouton droit
if (this.combo.getMode() == UNLOCKED || (ev.isControlDown() && this.combo.getMode() == ComboLockedMode.ITEMS_LOCKED)) {
this.popup.show(this.combo.getPopupComp(), ev.getX(), ev.getY());
// popups are never closed in a JComboBox (except when choosing a menu item)
if (SwingThreadUtils.getAncestorOrSelf(JComboBox.class, this.combo.getPopupComp()) != null)
addPopup(this.popup);
return this.popup;
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/ui/MenuUtils.java
51,6 → 51,10
* @throws IllegalArgumentException if path length is not odd.
*/
static public <C extends JComponent & MenuElement> JMenuItem addMenuItem(final Action action, final C topLevelMenu, final List<String> path) throws IllegalArgumentException {
return addMenuItem(new JMenuItem(action), topLevelMenu, path);
}
 
static public <C extends JComponent & MenuElement> JMenuItem addMenuItem(final JMenuItem mi, final C topLevelMenu, final List<String> path) throws IllegalArgumentException {
if (path.size() == 0 || path.size() % 2 == 0)
throw new IllegalArgumentException("Path should be of the form group/menu/group/... : " + path);
JComponent menu = topLevelMenu;
60,7 → 64,7
menu = addChild(menu, groupName, new JMenu(menuName), JMenu.class, false);
}
final String actionGroupName = path.get(path.size() - 1);
return addChild(menu, actionGroupName, new JMenuItem(action), JMenuItem.class, true);
return addChild(menu, actionGroupName, mi, JMenuItem.class, true);
}
 
static private Component[] getChildren(final Container c) {
/trunk/OpenConcerto/src/org/openconcerto/odtemplate/statements/ForEach.java
35,12 → 35,13
* ForEach tag: repeats a document element for each item in a collection. <br>
* Attributes:
* <ul>
* <li><b>element </b> (required): the document element to which this tag applies, e.g. "table-row"
* </li>
* <li><b>element </b> (required): the document element to which this tag applies, e.g. "table-row"</li>
* <li><b>items </b> (required): expression evaluating to a Collection to be iterated</li>
* <li><b>var </b> (required): variable name where the current iteration item is stored</li>
* <li><b>alternate </b> (optional): number of document elements to be alternated during iteration,
* tipically used for alternating row background colors with a value of "2"</li>
* typically used for alternating row background colors with a value of "2"</li>
* <li><b>multiple </b> (optional): number of document elements to be copied during iteration, not
* compatible with "alternate".</li>
* </ul>
*/
public class ForEach extends BaseStatement {
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/itemview/VWRowItemView.java
23,6 → 23,7
import org.openconcerto.utils.checks.EmptyObjFromVO;
import org.openconcerto.utils.checks.EmptyObjHelper;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.Component;
import java.beans.PropertyChangeListener;
107,8 → 108,9
 
// *** validObj
 
public final boolean isValidated() {
return this.getWrapper().isValidated();
@Override
public ValidState getValidState() {
return this.getWrapper().getValidState();
}
 
public final void addValidListener(ValidListener l) {
120,10 → 122,6
this.getWrapper().removeValidListener(new ChainValidListener(this, l));
}
 
public String getValidationText() {
return this.getWrapper().getValidationText();
}
 
public final Component getComp() {
return this.getWrapper().getComp();
}
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/ISQLElementWithCodeSelector.java
36,6 → 36,7
import org.openconcerto.utils.checks.EmptyObject;
import org.openconcerto.utils.checks.EmptyObjectHelper;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.doc.Documented;
 
import java.awt.Dimension;
284,8 → 285,9
}
 
@Override
public boolean isValidated() {
return true;
public ValidState getValidState() {
// return "aucun champ n'est sélectionné";
return ValidState.getTrueInstance();
}
 
@Override
436,12 → 438,6
return this.viewButton;
}
 
@Override
public String getValidationText() {
// TODO Auto-generated method stub
return "aucun champ n'est sélectionné";
}
 
/**
* Applique un filtre w sur le ISQLElementWithCode
*
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/JUniqueTextField.java
28,6 → 28,7
import org.openconcerto.ui.warning.JLabelWarning;
import org.openconcerto.utils.RTInterruptedException;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.doc.Documented;
import org.openconcerto.utils.text.SimpleDocumentListener;
 
336,8 → 337,9
this.supp.addValueListener(l);
}
 
public synchronized boolean isValidated() {
return this.isValidated;
@Override
public ValidState getValidState() {
return ValidState.createCached(this.isValidated, "Le numéro existe déjà");
}
 
private synchronized void runValidationThread() {
426,10 → 428,6
return false;
}
 
public String getValidationText() {
return "Le numéro existe déjà";
}
 
public JTextComponent getTextComp() {
return this.textField;
}
438,6 → 436,7
return this;
}
 
@Override
public void addValidListener(ValidListener l) {
this.supp.addValidListener(l);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/sqlobject/SQLRequestComboBox.java
34,6 → 34,7
import org.openconcerto.utils.checks.EmptyListener;
import org.openconcerto.utils.checks.EmptyObj;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.model.DefaultIMutableListModel;
 
import java.awt.Component;
85,7 → 86,7
protected final ISearchableCombo<IComboSelectionItem> combo;
 
// supports
private final ValueChangeSupport supp;
private final ValueChangeSupport<Integer> supp;
private final EmptyChangeSupport emptySupp;
 
// le mode actuel
149,8 → 150,12
this.uiInit(new IComboModel(req));
}
 
private boolean hasModel() {
return this.req != null;
}
 
public final void uiInit(final IComboModel req) {
if (this.req != null)
if (hasModel())
throw new IllegalStateException(this + " already inited.");
 
this.req = req;
222,6 → 227,9
// synchronize with the state of req (after adding our value listener)
this.modelValueChanged();
 
// getValidSate() depends on this.req
this.supp.fireValidChange();
 
this.uiLayout();
 
// *without* : resetValue() => doUpdateAll() since it was never filled
249,7 → 257,7
}
 
protected void updateListeners() {
if (this.req != null) {
if (hasModel()) {
this.req.setRunning(this.isDisplayable());
}
}
457,11 → 465,14
this.req.rmItemsListener(l);
}
 
public final boolean isValidated() {
// ok, since we fire every time the combo does (see our ctor)
return this.combo.isValidated();
@Override
public ValidState getValidState() {
// OK, since we fire every time the combo does (see our ctor)
// we are valid if we can return a value and getValue() needs this.req
return ValidState.getNoReasonInstance(hasModel()).and(this.combo.getValidState());
}
 
@Override
public final void addValidListener(ValidListener l) {
this.supp.addValidListener(l);
}
471,10 → 482,6
this.supp.removeValidListener(l);
}
 
public String getValidationText() {
return null;
}
 
private Icon getIconFor(IComboSelectionItem value) {
final Icon i;
if (value == null) {
/trunk/OpenConcerto/src/org/openconcerto/sql/element/ElementSQLObject.java
28,6 → 28,7
import org.openconcerto.utils.checks.ValidChangeSupport;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidObject;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.Component;
import java.beans.PropertyChangeListener;
72,7 → 73,7
this.comp.setNonExistantEditable(true);
// only uiInit() comp when necessary
this.comp.addValidListener(new ValidListener() {
public void validChange(ValidObject src, boolean newValue) {
public void validChange(ValidObject src, ValidState newValue) {
// don't fire if our objects change (eg combo reloading) while we're uncreated
if (isCreated()) {
ElementSQLObject.this.supp.firePropertyChange("value", null, null);
82,7 → 83,7
});
 
this.addValidListener(new ValidListener() {
public void validChange(ValidObject src, boolean newValue) {
public void validChange(ValidObject src, ValidState newValue) {
compChanged();
}
});
144,7 → 145,7
super.init(sqlName, fields);
this.helper = new EmptyObjectHelper(this, new Predicate() {
public boolean evaluate(Object object) {
return !getSQLChild().isInited() || !getSQLChild().isValidated();
return !getSQLChild().isInited() || !getSQLChild().getValidState().isValid();
}
});
}
271,21 → 272,17
}
}
 
public boolean isValidated() {
final boolean res;
@Override
public ValidState getValidState() {
final ValidState res;
if (isCreated()) {
res = this.comp.isValidated();
res = this.comp.getValidState();
} else {
res = true;
res = ValidState.getTrueInstance();
}
return res;
}
 
public String getValidationText() {
// TODO this.comp.getValidationText()
return null;
}
 
public void addValidListener(ValidListener l) {
this.validSupp.addValidListener(l);
}
296,7 → 293,7
}
 
private void fireValidChange() {
this.validSupp.fireValidChange(isValidated());
this.validSupp.fireValidChange(getValidState());
}
 
public void setEditable(boolean enabled) {
/trunk/OpenConcerto/src/org/openconcerto/sql/element/DefaultElementSQLObject.java
19,6 → 19,7
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidObject;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
60,7 → 61,7
super(parent, comp);
 
this.addValidListener(new ValidListener() {
public void validChange(ValidObject src, boolean newValue) {
public void validChange(ValidObject src, ValidState newValue) {
compChanged();
}
});
195,7 → 196,7
}
 
protected void compChanged() {
this.expandBtn.setEnabled(this.getCurrentID() != SQLRow.NONEXISTANT_ID && this.isValidated());
this.expandBtn.setEnabled(this.getCurrentID() != SQLRow.NONEXISTANT_ID && this.getValidState().isValid());
}
 
private final boolean isExpanded() {
/trunk/OpenConcerto/src/org/openconcerto/sql/element/SQLElement.java
35,8 → 35,7
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.sql.utils.SQLUtils.SQLFactory;
import org.openconcerto.sql.view.list.RowAction;
import org.openconcerto.sql.view.list.RowActionFactory;
import org.openconcerto.sql.view.list.IListeAction;
import org.openconcerto.sql.view.list.SQLTableModelColumn;
import org.openconcerto.sql.view.list.SQLTableModelColumnPath;
import org.openconcerto.sql.view.list.SQLTableModelSourceOnline;
52,7 → 51,6
import org.openconcerto.utils.change.ListChangeRecorder;
 
import java.awt.Component;
import java.awt.Container;
import java.lang.reflect.Constructor;
import java.sql.SQLException;
import java.util.ArrayList;
105,8 → 103,7
private ComboSQLRequest combo;
private ListSQLRequest list;
private SQLTableModelSourceOnline tableSrc;
private final ListChangeRecorder<RowAction> rowActions;
private final List<RowActionFactory> rowActionFactories;
private final ListChangeRecorder<IListeAction> rowActions;
// foreign fields
private Set<String> normalFF;
private String parentFF;
132,8 → 129,7
this.primaryTable = primaryTable;
this.combo = null;
this.list = null;
this.rowActions = new ListChangeRecorder<RowAction>(new ArrayList<RowAction>());
this.rowActionFactories = new ArrayList<RowActionFactory>();
this.rowActions = new ListChangeRecorder<IListeAction>(new ArrayList<IListeAction>());
this.actions = new HashMap<String, ReferenceAction>();
this.resetRelationships();
 
919,19 → 915,15
 
abstract protected List<String> getListFields();
 
public final Collection<RowAction> getRowActions() {
public final Collection<IListeAction> getRowActions() {
return this.rowActions;
}
 
public List<RowActionFactory> getRowActionFactories() {
return this.rowActionFactories;
}
 
public final void addRowActionsListener(final IClosure<ListChangeIndex<RowAction>> listener) {
public final void addRowActionsListener(final IClosure<ListChangeIndex<IListeAction>> listener) {
this.rowActions.getRecipe().addListener(listener);
}
 
public final void removeRowActionsListener(final IClosure<ListChangeIndex<RowAction>> listener) {
public final void removeRowActionsListener(final IClosure<ListChangeIndex<IListeAction>> listener) {
this.rowActions.getRecipe().rmListener(listener);
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/element/BaseSQLComponent.java
40,13 → 40,20
import org.openconcerto.ui.component.text.TextBehaviour;
import org.openconcerto.ui.component.text.TextComponentUtils;
import org.openconcerto.ui.coreanimation.Animator;
import org.openconcerto.ui.valuewrapper.ValidatedValueWrapper;
import org.openconcerto.ui.valuewrapper.ValueWrapper;
import org.openconcerto.ui.valuewrapper.ValueWrapperFactory;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.DecimalUtils;
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.cc.Transformer;
import org.openconcerto.utils.checks.EmptyListener;
import org.openconcerto.utils.checks.EmptyObj;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidObject;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.Component;
import java.awt.Dimension;
54,6 → 61,7
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
83,6 → 91,15
protected static final String DEC = "notdecorated";
protected static final String SEP = "noseparator";
 
/**
* Syntactic sugar for {@link BaseSQLComponent#createRowItemView(String, Class, ITransformer)}.
*
* @author Sylvain CUAZ
* @param <T> type parameter
*/
public static interface VWTransformer<T> extends ITransformer<ValueWrapper<? extends T>, ValueWrapper<? extends T>> {
}
 
private final SQLRowView requete;
 
private final Set<SQLRowItemView> required;
95,7 → 112,6
private boolean editable;
private boolean alwaysEditable;
private final Set<SQLField> hide;
private String invalidityCause;
private FormLayouter additionalFieldsPanel;
 
public BaseSQLComponent(SQLElement element) {
117,7 → 133,6
this.editable = true;
this.setNonExistantEditable(false);
this.requete = new SQLRowView(this.getTable());
this.invalidityCause = "";
}
 
private final SQLRowView getRequest() {
150,12 → 165,22
dobj.setDecorated(parser.isDecorated());
dobj.showSeparator(parser.showSeparator());
return this.addView((MutableRowItemView) dobj, field, parser);
} else if (getField(field).isKey()) {
// foreign
return this.addView(new ElementComboBox(), field, spec);
} else {
return this.addView(getComp(field).get0(), field, spec);
}
}
 
private Tuple2<JComponent, SQLType> getComp(String field) {
if (getElement().getPrivateElement(field) != null)
// we create a MutableRowItemView and need SpecParser
throw new IllegalArgumentException("Private fields not supported");
 
final JComponent comp;
final SQLType type = getField(field).getType();
if (getField(field).isKey()) {
// foreign
comp = new ElementComboBox();
} else {
if (Boolean.class.isAssignableFrom(type.getJavaType())) {
// TODO hack to view the focus (should try to paint around the button)
comp = new JCheckBox(" ");
166,8 → 191,8
else
// regular
comp = new SQLTextCombo();
return this.addView(comp, field, spec);
}
return new Tuple2<JComponent, SQLType>(comp, type);
}
 
public final void addSQLObject(JComponent obj, String field) {
204,15 → 229,75
static public SimpleRowItemView<?> createRowItemView(JComponent comp, final SQLField field) {
if (comp == null)
throw new NullPointerException("comp for " + field + " is null");
return createRowItemView(comp, field.getType().getJavaType());
if (comp instanceof MutableRowItemView)
throw new IllegalStateException("Comp is a MutableRowItemView, creating a SimpleRowItemView would ignore its methods : " + comp);
return createRowItemView(createValueWrapper(comp, field.getType(), Object.class));
}
 
// just to make javac happy (type parameter for SimpleRowItemView)
static private <T> SimpleRowItemView<T> createRowItemView(JComponent comp, final Class<T> javaType) {
return new SimpleRowItemView<T>(ValueWrapperFactory.create(comp, javaType));
static private <T> SimpleRowItemView<T> createRowItemView(ValueWrapper<T> vw) {
return new SimpleRowItemView<T>(vw);
}
 
static private <T> ValueWrapper<? extends T> createValueWrapper(JComponent comp, final SQLType type, final Class<T> wantedType) {
final Class<?> fieldClass = type.getJavaType();
ValueWrapper<? extends T> res = ValueWrapperFactory.create(comp, fieldClass.asSubclass(wantedType));
if (String.class.isAssignableFrom(fieldClass)) {
res = ValidatedValueWrapper.add(res, new ITransformer<T, ValidState>() {
@Override
public ValidState transformChecked(T t) {
final String s = (String) t;
final boolean ok = s == null || s.length() <= type.getSize();
// only compute string if needed
return ok ? ValidState.getTrueInstance() : ValidState.create(ok, "La valeur fait " + (s.length() - type.getSize()) + " caractère(s) de trop");
}
});
// other numeric SQL types are fixed size like their java counterparts
} else if (BigDecimal.class.isAssignableFrom(fieldClass)) {
final Integer decimalDigits = type.getDecimalDigits();
final int intDigits = type.getSize() - decimalDigits;
final String reason = "Nombre trop grand, il doit faire moins de " + intDigits + " chiffre(s) avant la virgule (" + decimalDigits + " après)";
res = ValidatedValueWrapper.add(res, new ITransformer<T, ValidState>() {
@Override
public ValidState transformChecked(T t) {
final BigDecimal bd = (BigDecimal) t;
// round first to get the correct number of integer digits, see
// http://www.postgresql.org/docs/8.4/interactive/datatype-numeric.html
return ValidState.create(bd == null || DecimalUtils.intDigits(DecimalUtils.round(bd, decimalDigits)) <= intDigits, reason);
}
});
}
return res;
}
 
public final <T> SimpleRowItemView<? extends T> createSimpleRowItemView(String fields, Class<T> clazz) {
return this.createSimpleRowItemView(fields, clazz, Transformer.<ValueWrapper<? extends T>> nopTransformer());
}
 
/**
* Create and initialize a SimpleRowItemView.
*
* @param <T> type of field.
* @param field field name.
* @param clazz java type for the field.
* @param init to initialize the value wrapper.
* @return the created row item view.
*/
public final <T> SimpleRowItemView<? extends T> createSimpleRowItemView(String field, Class<T> clazz, final ITransformer<? super ValueWrapper<? extends T>, ValueWrapper<? extends T>> init) {
final Tuple2<JComponent, SQLType> compNclass = this.getComp(field);
final JComponent comp = compNclass.get0();
final SQLType fieldClass = compNclass.get1();
if (comp instanceof MutableRowItemView)
throw new IllegalStateException("Comp is a MutableRowItemView, creating a SimpleRowItemView would ignore its methods : " + comp);
final ValueWrapper<? extends T> vw = createValueWrapper(comp, fieldClass, clazz);
return initRIV(createRowItemView(init.transformChecked(vw)), field);
}
 
public Component addView(MutableRowItemView rowItemView, String fields, Object specObj) {
return this.addInitedView(initRIV(rowItemView, fields), specObj);
}
 
private final <R extends MutableRowItemView> R initRIV(R rowItemView, String fields) {
final List<String> fieldListS = SQLRow.toList(fields);
final Set<SQLField> fieldList = new HashSet<SQLField>(fieldListS.size());
for (final String fieldName : fieldListS) {
223,8 → 308,7
final String sqlName = fields;
rowItemView.init(sqlName, fieldList);
rowItemView.setDescription(this.getLabelFor(sqlName));
 
return this.addInitedView(rowItemView, specObj);
return rowItemView;
}
 
public Component addInitedView(SQLRowItemView v, Object specObj) {
287,7 → 371,7
}
});
v.addValidListener(new ValidListener() {
public void validChange(ValidObject src, boolean newValue) {
public void validChange(ValidObject src, ValidState newValue) {
emptyOrValidChanged((SQLRowItemView) src);
}
});
355,7 → 439,7
 
protected synchronized final void fireValidChange() {
// ATTN called very often during a select() (for each SQLObject empty & value change)
final boolean validated = this.isValidated();
final ValidState validated = this.getValidState();
for (final ValidListener l : this.listeners) {
l.validChange(this, validated);
}
362,17 → 446,19
}
 
private boolean isItemViewValid(final SQLRowItemView v) {
return v.isValidated() && !(this.getRequired().contains(v) && v.isEmpty());
return v.getValidState().isValid() && !(this.getRequired().contains(v) && v.isEmpty());
}
 
public synchronized boolean isValidated() {
@Override
public synchronized ValidState getValidState() {
boolean res = true;
final List<String> pbs = new ArrayList<String>();
// tous nos objets sont valides ?
for (final SQLRowItemView obj : this.getRequest().getViews()) {
if (!obj.isValidated()) {
final ValidState state = obj.getValidState();
if (!state.isValid()) {
String explanation = "'" + getDesc(obj) + "' n'est pas valide";
final String txt = obj.getValidationText();
final String txt = state.getValidationText();
if (txt != null)
explanation += " (" + txt + ")";
pbs.add(explanation);
384,8 → 470,7
res = false;
}
}
this.invalidityCause = CollectionUtils.join(pbs, "\n");
return res;
return ValidState.create(res, CollectionUtils.join(pbs, "\n"));
}
 
protected static final String getDesc(final SQLRowItemView obj) {
393,10 → 478,6
return desc == null ? obj.getSQLName() : desc;
}
 
public String getValidationText() {
return this.invalidityCause;
}
 
/*
* (non-Javadoc)
*
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/ChangeTable.java
17,7 → 17,6
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLName;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLSyntax;
import org.openconcerto.sql.model.SQLSystem;
import org.openconcerto.sql.model.SQLTable;
344,7 → 343,7
* @see #addForeignColumn(String, SQLName, String, String)
*/
public T addForeignColumn(String fk, SQLTable foreignTable, final boolean absolute) {
final String defaultVal = foreignTable.getUndefinedID() == SQLRow.NONEXISTANT_ID ? "NULL" : foreignTable.getUndefinedID() + "";
final String defaultVal = foreignTable.getKey().getType().toString(foreignTable.getUndefinedIDNumber());
final SQLName n = absolute ? foreignTable.getSQLName() : new SQLName(foreignTable.getName());
return this.addForeignColumn(fk, n, foreignTable.getKey().getName(), defaultVal);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/utils/Exiter.java
14,8 → 14,8
package org.openconcerto.sql.utils;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.ui.UserExit;
 
import java.awt.Frame;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.Window;
67,11 → 67,6
 
public void closeAll() {
// dispose of every window (this will call windowClosed())
for (final Window f : Frame.getWindows()) {
if (f != this.main)
f.dispose();
UserExit.closeAllWindows(this.main);
}
// this is last to exit
this.main.dispose();
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/DBSystemRoot.java
60,7 → 60,6
 
this.supp = new PropertyChangeSupport(this);
this.coherenceListener = new PropertyChangeListener() {
@SuppressWarnings("unchecked")
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (isIncoherentPath())
67,6 → 66,7
// our path is empty so nothing can be removed
setRootPathFromDS();
else {
@SuppressWarnings("unchecked")
final Collection<String> newVal = (Collection<String>) evt.getNewValue();
final Collection<String> inexistant = CollectionUtils.substract(getRootPath(), newVal);
if (inexistant.size() > 0) {
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLTable.java
945,6 → 945,14
}
}
 
public final Number getUndefinedIDNumber() {
final int res = this.getUndefinedID();
if (res == SQLRow.NONEXISTANT_ID)
return null;
else
return res;
}
 
// save just this table
private final void save() {
// (for now save all tables)
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRowValuesListFetcher.java
471,7 → 471,6
return this.fetch(true);
}
 
@SuppressWarnings("unchecked")
private final List<SQLRowValues> fetch(final boolean merge) {
final SQLSelect req = this.getReq();
// getName() would take 5% of ResultSetHandler.handle()
495,6 → 494,7
});
assert l.size() == graphSize : "All nodes weren't explored once : " + l.size() + " != " + graphSize;
 
@SuppressWarnings("unchecked")
final List<SQLRowValues> res = (List<SQLRowValues>) table.getBase().getDataSource().execute(req.asString(), new ResultSetHandler() {
@Override
public Object handle(final ResultSet rs) throws SQLException {
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntax.java
433,8 → 433,17
sqlType = "text";
} else {
final String type = typeName.contains("var") ? "varchar" : "char";
sqlType = type + "(" + t.getSize() + ")";
final int size = t.getSize();
if (size < Integer.MAX_VALUE) {
sqlType = type + "(" + size + ")";
} else {
Log.get().warning("Unbounded varchar for " + f.getSQLName());
if (this.getSystem() == SQLSystem.MYSQL)
throw new IllegalStateException("MySQL doesn't support unbounded varchar and might truncate data if reducing size of " + f.getSQLName());
// don't specify size
sqlType = type;
}
}
} else if (t.getJavaType() == BigDecimal.class) {
sqlType = "DECIMAL(" + t.getSize() + "," + t.getDecimalDigits() + ")";
} else if (t.getJavaType() == Boolean.class) {
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLRow.java
358,7 → 358,6
* @param after whether to look before or after this row.
* @return a free order, or <code>null</code> if there's no room left.
*/
@SuppressWarnings("unchecked")
public final BigDecimal getOrder(boolean after) {
final SQLTable t = this.getTable();
final BigDecimal destOrder = this.getOrder();
377,6 → 376,7
 
final BigDecimal otherOrder;
final SQLDataSource ds = t.getBase().getDataSource();
@SuppressWarnings("unchecked")
final Map<String, Object> otherMap = ds.execute1(sel.asString());
if (otherMap != null) {
final SQLRow otherRow = new SQLRow(t, otherMap);
552,7 → 552,7
*/
public Set<SQLRow> getDistantRows(List<String> path) {
// on veut tous les champs de la derniere table et rien d'autre
final List<List<SQLField>> fields = new ArrayList<List<SQLField>>(Collections.nCopies(path.size() - 1, Collections.<SQLField> emptyList()));
final List<List<String>> fields = new ArrayList<List<String>>(Collections.nCopies(path.size() - 1, Collections.<String> emptyList()));
fields.add(null);
final Set<List<SQLRow>> s = this.getRowsOnPath(path, fields);
final Set<SQLRow> res = new LinkedHashSet<SQLRow>(s.size());
571,12 → 571,11
* @param fields un liste de des champs, chaque élément est :
* <ul>
* <li><code>null</code> pour tous les champs</li>
* <li>une String eg "DESIGNATION,NUMERO"</li>
* <li>une Collection de SQLField ou de nom complet de champs (prefixés)</li>
* <li>une Collection de nom de champs, e.g. ["DESIGNATION","NUMERO"]</li>
* </ul>
* @return un ensemble de List de SQLRow.
*/
public Set<List<SQLRow>> getRowsOnPath(final List<String> path, final List<?> fields) {
public Set<List<SQLRow>> getRowsOnPath(final List<String> path, final List<? extends Collection<String>> fields) {
final int pathSize = path.size();
if (pathSize == 0)
throw new IllegalArgumentException("path is empty");
595,18 → 594,16
 
final SQLSelect select = new SQLSelect(this.getTable().getBase());
 
final List<Collection> fieldsCols = new ArrayList<Collection>(pathSize);
final List<Collection<String>> fieldsCols = new ArrayList<Collection<String>>(pathSize);
for (int i = 0; i < pathSize; i++) {
final Object fieldsName = fields.get(i);
final Collection<String> tableFields = fields.get(i);
// +1 car p contient cette ligne
final SQLTable t = p.getTable(i + 1);
final Collection fieldsCol;
if (fieldsName == null) {
fieldsCol = t.getFields();
} else if (fieldsName instanceof String) {
fieldsCol = SQLRow.toList((String) fieldsName);
final Collection<String> fieldsCol;
if (tableFields == null) {
fieldsCol = t.getFieldsName();
} else {
fieldsCol = (Collection) fieldsName;
fieldsCol = tableFields;
}
fieldsCols.add(fieldsCol);
 
615,10 → 612,7
// toujours mettre l'ID
select.addSelect(t.getKey());
// plus les champs demandés
if (fieldsName instanceof String)
select.addAllSelect(t, fieldsCol);
else
select.addAllSelect(fieldsCol);
}
}
// dans tous les cas mettre l'ID de la dernière table
729,7 → 723,6
* @param fields the list of fields the rows will have, <code>null</code> meaning all.
* @return a List of SQLRow that points to this, eg [BATIMENT[123], BATIMENT[124]].
*/
@SuppressWarnings("unchecked")
public List<SQLRow> getReferentRows(final SQLField refField, final ArchiveMode archived, final Collection<String> fields) {
final SQLTable foreignTable = refField.getTable().getBase().getGraph().getForeignTable(refField);
if (!foreignTable.equals(this.getTable())) {
751,7 → 744,7
// - if some other criteria need to be applied, we could pass an SQLRowMode (instead of
// just ArchiveMode) and modify the SQLSelect accordingly
 
return (List<SQLRow>) this.getTable().getBase().getDataSource().execute(sel.asString(), new SQLRowListRSH(src, true));
return SQLRowListRSH.execute(sel);
}
 
/**
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntaxPG.java
49,6 → 49,20
import org.apache.commons.dbcp.DelegatingConnection;
import org.postgresql.PGConnection;
 
/**
* To require SSL, set the "ssl" connection property to "true" (note: for now any value, including
* "false" enables it), to disable server validation set "sslfactory" to
* "org.postgresql.ssl.NonValidatingFactory". To check the connection status, install the
* contrib/sslinfo extension and execute "select ssl_is_used();". SSL Compression might be supported
* if we can find a good sslfactory : see this <a
* href="http://archives.postgresql.org/pgsql-general/2010-08/thrd5.php#00003">thread</a>.
* <p>
* To enable SSL on the server see http://www.postgresql.org/docs/current/static/ssl-tcp.html
* (already set up on Ubuntu).
* <p>
*
* @author Sylvain CUAZ
*/
class SQLSyntaxPG extends SQLSyntax {
 
SQLSyntaxPG() {
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSelect.java
22,7 → 22,6
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
176,10 → 175,8
// si c'est null, ca marche
Where archive = this.where;
// ne pas exclure les archivés et les indéfinis des joins : SQLSelectJoin does it
final Collection fromAliases = CollectionUtils.substract(this.declaredTables.getAliases(), this.joinAliases);
final Iterator fromIter = fromAliases.iterator();
while (fromIter.hasNext()) {
final String alias = (String) fromIter.next();
final Collection<String> fromAliases = CollectionUtils.substract(this.declaredTables.getAliases(), this.joinAliases);
for (final String alias : fromAliases) {
final SQLTable fromTable = this.declaredTables.getTable(alias);
// on ignore les lignes archivées
archive = Where.and(getArchiveWhere(fromTable, alias), archive);
393,18 → 390,12
/**
* Permet d'ajouter plusieurs champs.
*
* @param s une collection soit de SQLField, soit de nom complet de champs.
* @param s une collection de FieldRef.
* @return this pour pouvoir chaîner.
*/
public SQLSelect addAllSelect(Collection s) {
for (Iterator iter = s.iterator(); iter.hasNext();) {
final Object element = iter.next();
if (element instanceof FieldRef)
this.addSelect((FieldRef) element);
else if (element instanceof String)
this.addSelect((String) element);
else
throw new ClassCastException("expecting SQLField or String, got :" + element);
public SQLSelect addAllSelect(Collection<? extends FieldRef> s) {
for (final FieldRef element : s) {
this.addSelect(element);
}
return this;
}
416,9 → 407,8
* @param s une collection de nom de champs, eg "NOM".
* @return this pour pouvoir chaîner.
*/
public SQLSelect addAllSelect(SQLTable t, Collection s) {
for (Iterator iter = s.iterator(); iter.hasNext();) {
final String fieldName = (String) iter.next();
public SQLSelect addAllSelect(SQLTable t, Collection<String> s) {
for (final String fieldName : s) {
this.addSelect(t.getField(fieldName));
}
return this;
458,7 → 448,7
*/
public SQLSelect addRawSelect(String expr, String alias) {
if (alias != null) {
expr += " as \"" + alias + "\"";
expr += " as " + SQLBase.quoteIdentifier(alias);
}
this.select.add(expr);
return this;
556,9 → 546,7
// une solution : ne calculer le from que dans asString() => marche pas car on s'en
// sert dans addOrder
if (this.whereAddToFrom && w != null) {
Iterator iter = w.getFields().iterator();
while (iter.hasNext()) {
FieldRef f = (FieldRef) iter.next();
for (final FieldRef f : w.getFields()) {
this.from.add(this.declaredTables.add(f));
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/model/graph/Link.java
153,11 → 153,11
pWriter.print("\"");
}
 
@SuppressWarnings("unchecked")
static Link fromXML(final SQLTable t, final Element linkElem) {
final SQLName to = SQLName.parse(linkElem.getAttributeValue("to"));
final SQLTable foreignTable = t.getDBSystemRoot().getDesc(to, SQLTable.class);
final String linkName = linkElem.getAttributeValue("name");
@SuppressWarnings("unchecked")
final List<Element> lElems = linkElem.getAttribute("col") != null ? singletonList(linkElem) : linkElem.getChildren("l");
final List<SQLField> cols = new ArrayList<SQLField>();
final List<SQLField> refcols = new ArrayList<SQLField>();
/trunk/OpenConcerto/src/org/openconcerto/sql/model/SQLSyntaxMySQL.java
15,9 → 15,9
 
import org.openconcerto.sql.model.SQLField.Properties;
import org.openconcerto.sql.model.SQLTable.Index;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.sql.utils.ChangeTable.ClauseType;
import org.openconcerto.sql.utils.ChangeTable.OutsideClause;
import org.openconcerto.sql.utils.SQLUtils;
import org.openconcerto.sql.utils.SQLUtils.SQLFactory;
import org.openconcerto.utils.CollectionMap;
import org.openconcerto.utils.CollectionUtils;
47,11 → 47,17
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Map.Entry;
 
import org.apache.commons.dbcp.DelegatingConnection;
 
/**
* MySQL can enable compression with the "useCompression" connection property. Compression status
* can be checked with "show global status like 'Compression';".
*
* @author Sylvain CUAZ
*/
class SQLSyntaxMySQL extends SQLSyntax {
 
SQLSyntaxMySQL() {
/trunk/OpenConcerto/src/org/openconcerto/sql/users/UserCommonSQLElement.java
27,6 → 27,7
import org.openconcerto.ui.ISpinnerIntegerModel;
import org.openconcerto.ui.warning.JLabelWarning;
import org.openconcerto.utils.CollectionMap;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.text.SimpleDocumentListener;
 
import java.awt.GridBagConstraints;
328,8 → 329,8
}
 
@Override
public synchronized boolean isValidated() {
return super.isValidated() && checkValidityPassword();
public synchronized ValidState getValidState() {
return super.getValidState().and(ValidState.createCached(checkValidityPassword(), "Les mots de passe ne correspondent pas"));
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/sql/changer/Convert.java
13,7 → 13,7
package org.openconcerto.sql.changer;
 
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.DBStructureItem;
 
import java.io.IOException;
import java.sql.SQLException;
24,7 → 24,7
super();
}
 
public Convert(DBRoot root) {
public Convert(DBStructureItem<?> root) {
super(root);
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/changer/convert/MergeTable.java
23,7 → 23,6
import org.openconcerto.sql.model.SQLDataSource;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLName;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSyntax;
120,9 → 119,9
// copy all data of t into destTable
final List<Number> insertedIDs = SQLRowValues.insertIDs(MergeTable.this.destTable, fields + " " + sel.asString());
// handle undefined
insertedIDs.add(0, MergeTable.this.destTable.getUndefinedID() == SQLRow.NONEXISTANT_ID ? null : MergeTable.this.destTable.getUndefinedID());
insertedIDs.add(0, MergeTable.this.destTable.getUndefinedIDNumber());
final List<Number> oldIDs = ds.executeCol(selOldIDs.asString());
final Integer oldUndef = t.getUndefinedID() == SQLRow.NONEXISTANT_ID ? null : t.getUndefinedID();
final Number oldUndef = t.getUndefinedIDNumber();
if (oldUndef == null)
// MAYBE should do a second update with "where %n is NULL"
throw new UnsupportedOperationException("old undef is null, not yet supported");
/trunk/OpenConcerto/src/org/openconcerto/sql/changer/convert/ToPrivate.java
New file
0,0 → 1,160
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.changer.convert;
 
import org.openconcerto.sql.changer.Changer;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.model.DBSystemRoot;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLName;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSystem;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.model.graph.SQLKey;
import org.openconcerto.sql.request.UpdateBuilder;
import org.openconcerto.sql.utils.AlterTable;
 
import java.sql.SQLException;
import java.util.EnumSet;
 
/**
* Convert one normal table to a table referenced by a private field. I.e. if you have table PARENT
* and two tables CHILD1, CHILD2 you may want to include CHILD2 into CHILD1 {@link SQLComponent} to
* reduce clutter. In that case {@link #PRIVATE_TABLE} is CHILD2, {@link #PARENT_FIELD} is
* "ID_PARENT" and {@link #PRIVATE_COUNT} must be the maximum CHILD2 there is per PARENT.
*
* @author Sylvain CUAZ
*/
public class ToPrivate extends Changer<SQLTable> {
 
static public final String PRIVATE_TABLE = "privateTable";
static public final String PARENT_FIELD = "parentField";
static public final String PRIVATE_COUNT = "privateCount";
 
private String privateTableName;
private String parentFieldName;
private int privateCount;
 
public ToPrivate(DBSystemRoot b) {
super(b);
}
 
@Override
protected EnumSet<SQLSystem> getCompatibleSystems() {
return EnumSet.of(SQLSystem.MYSQL);
}
 
@Override
public void setUpFromSystemProperties() {
super.setUpFromSystemProperties();
this.privateTableName = System.getProperty(PRIVATE_TABLE);
this.parentFieldName = System.getProperty(PARENT_FIELD);
this.privateCount = Integer.parseInt(System.getProperty(PRIVATE_COUNT, "1"));
}
 
public final String getPrivateField(int index) {
if (index < 0)
throw new IllegalArgumentException("negative: " + index);
else if (index == 0)
return SQLKey.PREFIX + this.privateTableName;
else
return SQLKey.PREFIX + this.privateTableName + "_" + (index + 1);
}
 
@Override
protected void changeImpl(final SQLTable tableToUpdate) throws SQLException {
final SQLTable privateTable = tableToUpdate.getTable(this.privateTableName);
 
// SELECT count(t1.ID_SITE)
// FROM INSTALLATIONS_ECL t1
// where t1.ARCHIVE = 0
// group by t1.ID_SITE
// having count(t1.ID_SITE) > 4
// order by count(t1.ID_SITE) DESC
// LIMIT 1;
final SQLField parentField = privateTable.getField(this.parentFieldName);
final SQLSelect checkCount = new SQLSelect(privateTable.getBase());
checkCount.addSelect(parentField, "count");
checkCount.addGroupBy(parentField);
final String countExpr = "count(" + SQLBase.quoteIdentifier(parentField.getName()) + ")";
checkCount.setHaving(Where.createRaw(countExpr + " > " + this.privateCount, parentField));
checkCount.addRawOrder(countExpr + " DESC");
checkCount.setLimit(1);
final Number n = (Number) getDS().executeScalar(checkCount.asString());
if (n != null) {
checkCount.addSelect(parentField);
checkCount.setLimit(null);
throw new IllegalStateException("More than " + this.privateCount + " rows : " + n + "\n" + checkCount.asString());
}
 
final AlterTable alter = new AlterTable(tableToUpdate);
for (int i = 0; i < this.privateCount; i++) {
final String privateFieldName = this.getPrivateField(i);
if (!tableToUpdate.contains(privateFieldName)) {
getStream().println("Creating " + privateFieldName + "...");
alter.addForeignColumn(privateFieldName, privateTable);
}
}
if (!alter.isEmpty()) {
getDS().execute(alter.asString());
tableToUpdate.getSchema().updateVersion();
tableToUpdate.fetchFields();
getStream().println("done.");
}
 
// select "ID_SITE", "ID count",
// case when "ID count" < 3 then NULL else SUBSTRING_INDEX(SUBSTRING_INDEX("IDs", '|', 3),
// '|', -1) end as "ID_3"
// from (
// SELECT "ID_SITE", COUNT("ID") as "ID count", cast( group_concat("ID" separator '|') as
// char) as "IDs"
// FROM INSTALLATIONS_ECL t1
// where t1.ARCHIVE = 0
// group by t1.ID_SITE
// ) aggregatedIDs;
final String sep = "','";
final SQLSelect groupIDs = new SQLSelect(privateTable.getBase());
groupIDs.addSelect(parentField);
groupIDs.addSelect(parentField, "count", "ID count");
final String quotedID = SQLBase.quoteIdentifier(privateTable.getKey().getName());
groupIDs.addRawSelect("cast( group_concat(" + quotedID + " separator " + sep + ") as char)", "IDs");
groupIDs.addGroupBy(parentField);
 
final Number undefIDobj = privateTable.getUndefinedIDNumber();
final String undefID = privateTable.getKey().getType().toString(undefIDobj);
final String quotedCount = SQLBase.quoteIdentifier("ID count");
final String quotedIDs = SQLBase.quoteIdentifier("IDs");
 
final UpdateBuilder update = new UpdateBuilder(tableToUpdate);
update.addTable("\n( " + groupIDs.asString() + " )", SQLBase.quoteIdentifier("aggregatedIDs"));
final String join = tableToUpdate.getBase().quote("%i = %f", new SQLName("aggregatedIDs", parentField.getName()), tableToUpdate.getField(this.parentFieldName));
Where dontOverwrite = null;
final StringBuilder splitIDs = new StringBuilder(256);
for (int i = 1; i <= this.privateCount; i++) {
final String privateFieldName = getPrivateField(i - 1);
dontOverwrite = new Where(tableToUpdate.getField(privateFieldName), Where.NULL_IS_DATA_EQ, undefIDobj).and(dontOverwrite);
 
splitIDs.setLength(0);
splitIDs.append("case when ").append(quotedCount).append(" < ").append(i).append(" then ").append(undefID);
splitIDs.append(" else SUBSTRING_INDEX(SUBSTRING_INDEX(").append(quotedIDs).append(", " + sep + ", ").append(i).append("), " + sep + ", -1) end ");
update.set(privateFieldName, splitIDs.toString());
}
update.setWhere(Where.createRaw(join).and(dontOverwrite));
 
// ATTN for some reason the MySQL JDBC driver doesn't to execute this
getStream().println(update.toString());
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/changer/Correct.java
13,7 → 13,7
package org.openconcerto.sql.changer;
 
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.DBStructureItem;
 
import java.io.IOException;
import java.sql.SQLException;
24,7 → 24,7
super();
}
 
public Correct(DBRoot root) {
public Correct(DBStructureItem<?> root) {
super(root);
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/changer/Change.java
14,8 → 14,9
package org.openconcerto.sql.changer;
 
import org.openconcerto.sql.PropsConfiguration;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.DBStructureItem;
import org.openconcerto.sql.model.DBSystemRoot;
import org.openconcerto.sql.model.SQLName;
import org.openconcerto.utils.StringUtils;
 
import java.io.File;
22,8 → 23,10
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
 
public abstract class Change {
 
33,9 → 36,9
props.put(PropsConfiguration.JDBC_CONNECTION + "allowMultiQueries", "true");
}
 
protected final DBRoot root;
protected final DBStructureItem<?> root;
 
protected Change(final DBRoot root) {
protected Change(final DBStructureItem<?> root) {
this.root = root;
}
 
43,14 → 46,6
this(new PropsConfiguration(new File("changeBase.properties"), props).getRoot());
}
 
protected final DBRoot getRoot() {
return this.root;
}
 
protected final SQLBase getBase() {
return this.getRoot().getBase();
}
 
protected final void exec(String... nameNparams) throws SQLException {
if (nameNparams.length == 0)
throw new IllegalArgumentException("usage: " + this.getClass().getName() + " changer params...");
69,12 → 64,25
}
 
public void exec(final Class<? extends Changer> changer, String... params) throws SQLException {
if (params.length == 0)
if (params.length == 0) {
Changer.change(this.root, changer);
else
for (final String table : params)
Changer.change(this.root.getTable(table), changer);
} else {
final List<SQLName> names = new ArrayList<SQLName>(params.length);
final Set<String> children = new HashSet<String>();
for (final String name : params) {
final SQLName n = SQLName.parse(name);
names.add(n);
children.add(n.getFirst());
}
if (this.root instanceof DBSystemRoot) {
final DBSystemRoot sysRoot = (DBSystemRoot) this.root;
if (!sysRoot.getRootsToMap().containsAll(children))
sysRoot.addRoots(new ArrayList<String>(children));
}
for (final SQLName name : names)
Changer.change(this.root.getDescendant(name), changer);
}
}
 
public final Class<? extends Changer> findClass(final String converter) {
final String normalized = StringUtils.firstUp(converter);
/trunk/OpenConcerto/src/org/openconcerto/sql/view/listview/ListSQLView.java
26,6 → 26,7
import org.openconcerto.utils.checks.EmptyObjectHelper;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidObject;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.Component;
import java.awt.GridBagConstraints;
77,7 → 78,7
this.items = new ArrayList<ListItemSQLView>();
 
this.addValidListener(new ValidListener() {
public void validChange(ValidObject src, boolean newValue) {
public void validChange(ValidObject src, ValidState newValue) {
// compChanged(); FIXME
}
});
254,7 → 255,8
this.supp.addPropertyChangeListener(l);
}
 
public boolean isValidated() {
@Override
public ValidState getValidState() {
return this.getPool().isValidated();
}
 
267,8 → 269,4
this.getPool().removeValidListener(l);
}
 
public String getValidationText() {
return null;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/listview/ItemPool.java
17,6 → 17,7
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.request.SQLRowItemView;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
 
import java.util.Collection;
import java.util.HashSet;
122,19 → 123,19
 
protected synchronized final void fireValidChange() {
// ATTN called very often during a select() (for each SQLObject empty & value change)
final boolean validated = this.isValidated();
final ValidState validated = this.isValidated();
for (final ValidListener l : this.validListeners) {
l.validChange(this.getPanel(), validated);
}
}
 
final boolean isValidated() {
final ValidState isValidated() {
// si la liste est vide, elle est valide
boolean res = true;
ValidState res = ValidState.getTrueInstance();
final Iterator<SQLRowItemView> iter = this.getItems().iterator();
while (iter.hasNext() && res) {
while (iter.hasNext()) {
final SQLRowItemView v = iter.next();
res = v.isValidated();
res = res.and(v.getValidState());
}
return res;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/IListe.java
29,12 → 29,17
import org.openconcerto.sql.request.ListSQLRequest;
import org.openconcerto.sql.view.FileTransfertHandler;
import org.openconcerto.sql.view.IListener;
import org.openconcerto.sql.view.list.RowAction.LimitedSizeRowAction;
import org.openconcerto.sql.view.list.IListeAction.ButtonsBuilder;
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
import org.openconcerto.sql.view.list.IListeAction.PopupBuilder;
import org.openconcerto.sql.view.list.IListeAction.PopupEvent;
import org.openconcerto.sql.view.list.RowAction.PredicateRowAction;
import org.openconcerto.sql.view.search.ColumnSearchSpec;
import org.openconcerto.sql.view.search.SearchList;
import org.openconcerto.ui.FontUtils;
import org.openconcerto.ui.FormatEditor;
import org.openconcerto.ui.MenuUtils;
import org.openconcerto.ui.PopupMouseListener;
import org.openconcerto.ui.SwingThreadUtils;
import org.openconcerto.ui.list.selection.ListSelection;
import org.openconcerto.ui.list.selection.ListSelectionState;
50,6 → 55,7
import org.openconcerto.utils.TableModelSelectionAdapter;
import org.openconcerto.utils.TableSorter;
import org.openconcerto.utils.Tuple2;
import org.openconcerto.utils.cc.IPredicate;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.convertor.StringClobConvertor;
 
81,10 → 87,12
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EventObject;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
 
import javax.swing.AbstractAction;
155,7 → 163,7
FORCE_ALT_CELL_RENDERER = force;
}
 
public static final IListe get(ActionEvent evt) {
public static final IListe get(EventObject evt) {
return SwingThreadUtils.getAncestorOrSelf(IListe.class, (Component) evt.getSource());
}
 
173,9 → 181,9
private boolean adjustVisible;
private ColumnSizeAdjustor tcsa;
 
private final Map<RowAction, JButton> rowActions;
private final Map<IListeAction, ButtonsBuilder> rowActions;
// double-click
private RowAction defaultRowAction;
private IListeAction defaultRowAction;
private final JPanel btnPanel;
 
// * selection
193,8 → 201,9
 
private final ListSelectionState state;
private final JTableStateManager tableStateManager;
private List<RowActionFactory> rowActionFactories = new ArrayList<RowActionFactory>(0);
 
private int retainCount = 0;
 
public IListe(final ListSQLRequest req) {
this(req, null);
}
215,7 → 224,7
if (req == null)
throw new NullPointerException("Création d'une IListe avec une requete null");
 
this.rowActions = new LinkedHashMap<RowAction, JButton>();
this.rowActions = new LinkedHashMap<IListeAction, ButtonsBuilder>();
this.supp = new PropertyChangeSupport(this);
this.listeners = new ArrayList<IListener>();
this.naListeners = new ArrayList<IListener>();
303,7 → 312,7
TablePopupMouseListener.add(this.jTable, new ITransformer<MouseEvent, JPopupMenu>() {
@Override
public JPopupMenu transformChecked(MouseEvent input) {
return updatePopupMenu();
return updatePopupMenu(true);
}
});
this.jTable.addMouseListener(new MouseAdapter() {
363,6 → 372,14
// donc on ne peut faire aucune action pendant les maj
 
this.btnPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
this.addModelListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
// let the header buttons know that the rows have changed
if ("updating".equals(evt.getPropertyName()) && Boolean.FALSE.equals(evt.getNewValue()))
updateButtons();
}
});
 
uiInit();
}
378,38 → 395,55
 
public final RowAction addRowAction(Action action) {
// for backward compatibility don't put in header
final RowAction res = new LimitedSizeRowAction(action, false, true);
this.addRowAction(res);
final RowAction res = new PredicateRowAction(action, false, true).setPredicate(IListeEvent.getSingleSelectionPredicate());
this.addIListeAction(res);
return res;
}
 
public final void addRowActions(Collection<RowAction> actions) {
for (final RowAction a : actions)
this.addRowAction(a);
public final void addIListeActions(Collection<? extends IListeAction> actions) {
for (final IListeAction a : actions)
this.addIListeAction(a);
}
 
public void addRowActionFactories(List<RowActionFactory> rowActionFactories) {
this.rowActionFactories.addAll(rowActionFactories);
private final int findGroupIndex(final String groupName) {
if (groupName != null) {
final Component[] components = this.btnPanel.getComponents();
for (int i = components.length - 1; i >= 0; i--) {
final JComponent comp = (JComponent) components[i];
if (groupName.equals(comp.getClientProperty(ButtonsBuilder.GROUPNAME_PROPNAME))) {
return i + 1;
}
}
}
return -1;
}
 
public final void addRowAction(RowAction action) {
final JButton headerBtn = action.inHeader() ? new JButton(action.getAction()) : null;
this.rowActions.put(action, headerBtn);
if (headerBtn != null) {
this.updateButton(action, getSelectedRows());
this.btnPanel.add(headerBtn);
public final void addIListeAction(IListeAction action) {
// we need to handle addition of an already added action at least for setDefaultRowAction()
if (this.rowActions.containsKey(action))
return;
final ButtonsBuilder headerBtns = action.getHeaderButtons();
this.rowActions.put(action, headerBtns);
if (headerBtns.getContent().size() > 0) {
updateButton(headerBtns, new IListeEvent(this));
for (final JButton headerBtn : headerBtns.getContent().keySet()) {
this.btnPanel.add(headerBtn, findGroupIndex((String) headerBtn.getClientProperty(ButtonsBuilder.GROUPNAME_PROPNAME)));
}
this.btnPanel.setVisible(true);
}
}
 
public final void removeRowActions(Collection<RowAction> actions) {
for (final RowAction a : actions)
this.removeRowAction(a);
public final void removeIListeActions(Collection<? extends IListeAction> actions) {
for (final IListeAction a : actions)
this.removeIListeAction(a);
}
 
public final void removeRowAction(RowAction action) {
final JButton headerBtn = this.rowActions.remove(action);
if (headerBtn != null) {
public final void removeIListeAction(IListeAction action) {
final ButtonsBuilder headerBtns = this.rowActions.remove(action);
// handle the removal of inexistent action (ButtonsBuilder can not be null)
if (headerBtns == null)
return;
for (final JButton headerBtn : headerBtns.getContent().keySet()) {
this.btnPanel.remove(headerBtn);
if (this.btnPanel.getComponentCount() == 0)
this.btnPanel.setVisible(false);
416,74 → 450,74
this.btnPanel.revalidate();
}
if (action.equals(this.defaultRowAction))
this.defaultRowAction = null;
this.setDefaultRowAction(null);
}
 
public void removeRowActionFactories(List<RowActionFactory> rowActionFactories2) {
// TODO Auto-generated method stub
}
 
private void updateButtons() {
final List<SQLRowAccessor> selectedRows = getSelectedRows();
for (final RowAction action : this.rowActions.keySet()) {
this.updateButton(action, selectedRows);
final IListeEvent evt = new IListeEvent(this);
for (final ButtonsBuilder btns : this.rowActions.values()) {
this.updateButton(btns, evt);
}
}
 
private JButton updateButton(final RowAction action, List<SQLRowAccessor> selectedRows) {
final JButton btn = this.rowActions.get(action);
if (btn != null) {
btn.setEnabled(action.enabledFor(selectedRows));
private void updateButton(final ButtonsBuilder btns, final IListeEvent evt) {
for (final Entry<JButton, IPredicate<IListeEvent>> e : btns.getContent().entrySet()) {
e.getKey().setEnabled(e.getValue().evaluateChecked(evt));
}
return btn;
}
 
private JPopupMenu updatePopupMenu() {
private JPopupMenu updatePopupMenu(final boolean onRows) {
this.popup.removeAll();
final List<SQLRowAccessor> selectedRows = getSelectedRows();
List<RowAction> actions = new ArrayList<RowAction>();
actions.addAll(this.rowActions.keySet());
final int size = this.rowActionFactories.size();
for (int i = 0; i < size; i++) {
RowActionFactory f = this.rowActionFactories.get(i);
List<RowAction> l = f.createActions(selectedRows);
if (l != null) {
actions.addAll(l);
final PopupEvent evt = new PopupEvent(this, onRows);
final Action defaultAction = this.defaultRowAction != null ? this.defaultRowAction.getDefaultAction(evt) : null;
final VirtualMenu menu = VirtualMenu.createRoot(null);
for (final IListeAction a : this.rowActions.keySet()) {
final PopupBuilder popupContent = a.getPopupContent(evt);
if (defaultAction != null && a == this.defaultRowAction) {
// Cannot compare actions since menu items are not required to have an action
// If popup actions are ["Dial 03", "Dial 06"] then getDefaultAction() cannot always
// return the same instance "if land line is default then Dial 03 else Dial 06"
// otherwise we can't find its matching menu item in the popup
final JMenuItem defaultMI = popupContent.getRootMenuItem(defaultAction);
if (defaultMI == null)
Log.get().warning("Default action not found at the root level of popup for " + this);
else
defaultMI.setFont(defaultMI.getFont().deriveFont(Font.BOLD));
}
menu.merge(popupContent.getMenu());
}
 
for (final RowAction a : actions) {
if (a.inPopupMenu()) {
final JMenuItem menuItem = MenuUtils.addMenuItem(a.getAction(), this.popup, a.getPath());
if (a.equals(this.defaultRowAction))
menuItem.setFont(menuItem.getFont().deriveFont(Font.BOLD));
menuItem.setEnabled(a.enabledFor(selectedRows));
for (final Entry<JMenuItem, List<String>> e : menu.getContent().entrySet()) {
MenuUtils.addMenuItem(e.getKey(), this.popup, e.getValue());
}
}
 
return this.popup;
}
 
/**
* Set the action performed when double-clicking a row. This method calls
* {@link #addRowAction(Action)} and the popup display this action distinctively.
* Set the action performed when double-clicking a row.
*
* @param action the default action.
* @param action the default action, can be <code>null</code>.
*/
public final void setDefaultRowAction(final RowAction action) {
if (action != null && !this.rowActions.containsKey(action))
this.addRowAction(action);
public final void setDefaultRowAction(final IListeAction action) {
this.defaultRowAction = action;
if (action != null)
this.addIListeAction(action);
}
 
public final RowAction getDefaultRowAction() {
public final IListeAction getDefaultRowAction() {
return this.defaultRowAction;
}
 
private void performDefaultAction(MouseEvent e) {
if (this.defaultRowAction != null && this.defaultRowAction.enabledFor(getSelectedRows()))
this.defaultRowAction.getAction().actionPerformed(new ActionEvent(e.getSource(), e.getID(), null, e.getWhen(), e.getModifiers()));
// special method needed since sometimes getPopupContent() can access the DB (optionally
// creating threads) or be slow
if (this.defaultRowAction != null) {
final Action defaultAction = this.defaultRowAction.getDefaultAction(new IListeEvent(this));
if (defaultAction != null)
defaultAction.actionPerformed(new ActionEvent(e.getSource(), e.getID(), null, e.getWhen(), e.getModifiers()));
}
}
 
private void uiInit() {
// * filter
593,6 → 627,12
 
final JScrollPane scrollPane = new JScrollPane(this.jTable);
scrollPane.setFocusable(false);
scrollPane.addMouseListener(new PopupMouseListener() {
@Override
protected JPopupMenu createPopup(MouseEvent e) {
return updatePopupMenu(false);
}
});
 
this.setLayout(new GridBagLayout());
final GridBagConstraints c = new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0);
924,18 → 964,26
 
// *** Ancestors ***//
 
@Override
public void ancestorAdded(AncestorEvent event) {
if (event.getAncestor().isVisible())
// there was an if added in r989, but from the javadoc it isn't needed
assert event.getAncestor().isVisible();
// ancestorAdded means we've just been added to a visible hierarchy, not that we were added
// to our parent
this.getModel().setSleeping(false);
}
 
@Override
public void ancestorRemoved(AncestorEvent event) {
// test isDead() since in JComponent.removeNotify() first setDisplayable(false) (in super)
// then firePropertyChange("ancestor", null).
if (!this.isDead() && !event.getAncestor().isVisible())
// thus we can still be visible while not displayable anymore
assert !event.getAncestor().isVisible() || !event.getAncestor().isDisplayable();
if (!this.isDead())
this.getModel().setSleeping(true);
}
 
@Override
public void ancestorMoved(AncestorEvent event) {
// nothing to do
}
1064,13 → 1112,30
* listener of SQLTable which will never be gc'd.
*/
private final void dispChanged() {
if (!this.isDisplayable()) {
final boolean requiredToLive = this.isDisplayable() || this.retainCount > 0;
if (!requiredToLive && !this.isDead()) {
this.setTableModel(null);
} else {
this.setSource(this.src);
} else if (requiredToLive && this.isDead()) {
this.setTableModel(new ITableModel(this.src));
}
}
 
/**
* Allow this to stay alive even if undisplayable. Attention, you must call {@link #release()}
* for each {@link #retain()} otherwise this instance will never be garbage collected.
*/
public final void retain() {
this.retainCount++;
this.dispChanged();
}
 
public final void release() {
if (this.retainCount == 0)
throw new IllegalStateException("Unbalanced release");
this.retainCount--;
this.dispChanged();
}
 
public JTable getJTable() {
return this.jTable;
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowAction.java
15,6 → 15,7
 
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.cc.IPredicate;
 
import java.awt.event.ActionEvent;
import java.util.ArrayList;
25,14 → 26,17
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JMenuItem;
 
/**
* An action that act on rows of a {@link IListe}.
* An action that act on rows of a {@link IListe}. Either {@link #enabledFor(IListeEvent)} or
* {@link #enabledFor(List)} must be overloaded.
*
* @author Sylvain CUAZ
* @see IListe#addRowAction(RowAction)
* @see IListe#addIListeAction(RowAction)
*/
public abstract class RowAction {
public abstract class RowAction implements IListeAction {
 
public static Action createAction(String name, Icon icon, final IClosure<List<SQLRowAccessor>> action) {
return new AbstractAction(name, icon) {
43,39 → 47,29
};
}
 
public static class LimitedSizeRowAction extends RowAction {
private int minSize = 1;
private int maxSize = Integer.MAX_VALUE;
public static class PredicateRowAction extends RowAction {
private IPredicate<? super IListeEvent> pred = null;
 
public LimitedSizeRowAction(Action action, boolean header) {
public PredicateRowAction(Action action, boolean header) {
super(action, header);
}
 
public LimitedSizeRowAction(Action action, boolean header, boolean popupMenu) {
public PredicateRowAction(Action action, boolean header, boolean popupMenu) {
super(action, header, popupMenu);
}
 
public final int getMinSize() {
return this.minSize;
}
 
public final LimitedSizeRowAction setMinSize(int minSize) {
this.minSize = minSize;
public final PredicateRowAction setPredicate(IPredicate<? super IListeEvent> pred) {
this.pred = pred;
return this;
}
 
public final int getMaxSize() {
return this.maxSize;
public final IPredicate<? super IListeEvent> getPredicate() {
return this.pred;
}
 
public final LimitedSizeRowAction setMaxSize(int maxSize) {
this.maxSize = maxSize;
return this;
}
 
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return selection.size() >= this.minSize && selection.size() <= this.maxSize;
public boolean enabledFor(IListeEvent evt) {
return this.pred.evaluateChecked(evt);
}
}
 
121,5 → 115,45
return this.path;
}
 
public abstract boolean enabledFor(List<SQLRowAccessor> selection);
public boolean enabledFor(List<SQLRowAccessor> selection) {
throw new UnsupportedOperationException("Should overload this method or enabledFor(IListeEvent)");
}
 
/**
* Whether the action should be enabled in the header or in the popup.
*
* @param evt the state of the IListe.
* @return <code>true</code> if the action can be performed.
*/
public boolean enabledFor(IListeEvent evt) {
return this.enabledFor(evt.getSelectedRows());
}
 
@Override
public ButtonsBuilder getHeaderButtons() {
return !this.inHeader() ? ButtonsBuilder.emptyInstance() : new ButtonsBuilder().add(new JButton(getAction()), new IPredicate<IListeEvent>() {
@Override
public boolean evaluateChecked(IListeEvent evt) {
return enabledFor(evt);
}
});
}
 
@Override
public Action getDefaultAction(IListeEvent evt) {
return null;
}
 
@Override
public PopupBuilder getPopupContent(PopupEvent evt) {
if (this.inPopupMenu() && evt.isClickOnRows()) {
final JMenuItem mi = new JMenuItem(getAction());
mi.setEnabled(this.enabledFor(evt));
final PopupBuilder res = new PopupBuilder();
res.getMenu().addItem(mi, getPath());
return res;
} else {
return PopupBuilder.emptyInstance();
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowValuesTableModel.java
17,7 → 17,6
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLRowValues;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.UndefinedRowValuesCache;
441,15 → 440,11
SQLRowValues row = this.rowValues.get(index);
 
if (this.requiredField.isKey()) {
SQLRowAccessor rowAccess = row.getForeign(this.requiredField.getName());
return (rowAccess != null && rowAccess.getID() > rowAccess.getTable().getUndefinedID());
}
 
return !row.isForeignEmpty(this.requiredField.getName());
} else {
final Object object = row.getObject(this.requiredField.getName());
if (object != null && object.toString().trim().length() > 0) {
return true;
return object != null && object.toString().trim().length() > 0;
}
return false;
}
 
public boolean isValidated() {
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/ITableModel.java
116,6 → 116,7
// sleep state
private SleepState wantedState;
private SleepState actualState;
private int hibernateDelay;
private TimerTask autoHibernate;
// number of runnables needing our queue to be awake
private final AtomicInteger runSleep;
167,6 → 168,7
});
this.actualState = SleepState.AWAKE;
this.wantedState = this.actualState;
this.setHibernateDelay(30);
this.autoHibernate = null;
this.runSleep = new AtomicInteger(0);
this.searchQ = new SearchQueue(new ListAccess(this));
548,6 → 550,16
}
}
 
/**
* Set the number of seconds between reaching the {@link SleepState#SLEEPING} state and setting
* the {@link SleepState#HIBERNATING} state.
*
* @param seconds the number of seconds, less than 0 to disable automatic hibernating.
*/
public final void setHibernateDelay(int seconds) {
this.hibernateDelay = seconds;
}
 
private void runnableAdded() {
synchronized (this.runSleep) {
this.runSleep.incrementAndGet();
602,6 → 614,7
break;
case SLEEPING:
this.updateQ.setSleeping(true);
if (this.hibernateDelay >= 0) {
this.autoHibernate = new TimerTask() {
@Override
public void run() {
608,7 → 621,8
setSleeping(HIBERNATING);
}
};
getAutoHibernateTimer().schedule(this.autoHibernate, 30 * 1000);
getAutoHibernateTimer().schedule(this.autoHibernate, this.hibernateDelay * 1000);
}
break;
case HIBERNATING:
this.updateQ.putRemoveAll();
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/IListeAction.java
New file
0,0 → 1,290
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.view.list;
 
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.ui.list.selection.ListSelection;
import org.openconcerto.utils.CollectionUtils;
import org.openconcerto.utils.cc.IPredicate;
 
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
 
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JMenuItem;
 
/**
* Actions that can be performed with an {@link IListe}.
*
* @author Sylvain CUAZ
*/
public interface IListeAction {
 
static public class IListeEvent {
 
static private final IPredicate<IListeEvent> emptyTotalRowCountPredicate = createTotalRowCountPredicate(0, 0);
 
static public final IPredicate<IListeEvent> getEmptyListPredicate() {
return emptyTotalRowCountPredicate;
}
 
static public final IPredicate<IListeEvent> createTotalRowCountPredicate(final int min, final int max) {
return new IPredicate<IListeEvent>() {
@Override
public boolean evaluateChecked(IListeEvent e) {
return e.getTotalRowCount() >= min && e.getTotalRowCount() <= max;
}
};
}
 
static private final IPredicate<IListeEvent> singleSelectionPredicate = createSelectionCountPredicate(1, 1);
static private final IPredicate<IListeEvent> nonEmptySelectionPredicate = createNonEmptySelectionPredicate(Integer.MAX_VALUE);
 
static public final IPredicate<IListeEvent> getSingleSelectionPredicate() {
return singleSelectionPredicate;
}
 
static public final IPredicate<IListeEvent> getNonEmptySelectionPredicate() {
return nonEmptySelectionPredicate;
}
 
static public final IPredicate<IListeEvent> createNonEmptySelectionPredicate(final int max) {
return createSelectionCountPredicate(1, max);
}
 
static public final IPredicate<IListeEvent> createSelectionCountPredicate(final int min, final int max) {
return new IPredicate<IListeEvent>() {
@Override
public boolean evaluateChecked(IListeEvent e) {
// this is the fastest since it involves no object creation
final List<?> selectedIDs = e.getSelectedRows();
return selectedIDs.size() >= min && selectedIDs.size() <= max;
}
};
}
 
private final IListe list;
private final List<SQLRowAccessor> selection;
 
IListeEvent(final IListe list) {
super();
this.list = list;
// this create instances so cache it
this.selection = list.getSelectedRows();
}
 
public final SQLRowAccessor getSelectedRow() {
return CollectionUtils.getFirst(this.getSelectedRows());
}
 
public final List<SQLRowAccessor> getSelectedRows() {
return this.selection;
}
 
public final int getTotalRowCount() {
return this.list.getTotalRowCount();
}
 
public final ListSelection getSelection() {
return this.list.getSelection();
}
 
public final SQLTable getTable() {
return this.list.getSource().getPrimaryTable();
}
}
 
/**
* Allow to build a list of buttons and when to enable/disable them.
*
* @author Sylvain CUAZ
*/
static public class ButtonsBuilder {
 
static final String GROUPNAME_PROPNAME = "GROUPNAME";
 
static private final ButtonsBuilder NO_BUTTONS = new ButtonsBuilder(Collections.<JButton, IPredicate<IListeEvent>> emptyMap());
 
static public final ButtonsBuilder emptyInstance() {
return NO_BUTTONS;
}
 
private final Map<JButton, IPredicate<IListeEvent>> map;
private String defaultGroup;
 
public ButtonsBuilder() {
this(new LinkedHashMap<JButton, IPredicate<IListeEvent>>());
}
 
private ButtonsBuilder(Map<JButton, IPredicate<IListeEvent>> map) {
super();
this.map = map;
this.defaultGroup = null;
}
 
public final String getDefaultGroup() {
return this.defaultGroup;
}
 
public ButtonsBuilder setDefaultGroup(String defaultGroup) {
this.defaultGroup = defaultGroup;
return this;
}
 
public final ButtonsBuilder add(JButton btn) {
return this.add(btn, IPredicate.<IListeEvent> truePredicate());
}
 
public final ButtonsBuilder add(JButton btn, IPredicate<IListeEvent> pred) {
return this.add(btn, pred, getDefaultGroup());
}
 
/**
* Add a button in the passed group.
*
* @param btn the button to add.
* @param pred should return <code>true</code> when the button must be enabled.
* @param group the group in which to put the button.
* @return this.
*/
public final ButtonsBuilder add(JButton btn, IPredicate<IListeEvent> pred, final String group) {
btn.putClientProperty(GROUPNAME_PROPNAME, group);
this.map.put(btn, pred);
return this;
}
 
// * getter
 
Map<JButton, IPredicate<IListeEvent>> getContent() {
return this.map;
}
}
 
static public class PopupEvent extends IListeEvent {
 
private final boolean clickOnRows;
 
PopupEvent(final IListe list, final boolean clickOnRows) {
super(list);
this.clickOnRows = clickOnRows;
}
 
public final boolean isClickOnRows() {
return this.clickOnRows;
}
}
 
/**
* Allow to build a hierarchical menu.
*
* @author Sylvain CUAZ
*/
static public class PopupBuilder {
static private final PopupBuilder EmptyInstance = new PopupBuilder(VirtualMenu.EMPTY);
 
static public final PopupBuilder emptyInstance() {
return EmptyInstance;
}
 
private final VirtualMenu rootMenu;
 
public PopupBuilder() {
this((String) null);
}
 
public PopupBuilder(final String defaultGroup) {
this(VirtualMenu.createRoot(defaultGroup));
}
 
private PopupBuilder(final VirtualMenu rootMenu) {
this.rootMenu = rootMenu;
}
 
/**
* Get the root menu of the popup.
*
* @return the menu at the root.
*/
public final VirtualMenu getMenu() {
return this.rootMenu;
}
 
public final String getDefaultGroup() {
return this.getMenu().getDefaultGroupName();
}
 
final JMenuItem getRootMenuItem(final Action defaultAction) {
String actionCommand = (String) defaultAction.getValue(Action.ACTION_COMMAND_KEY);
if (actionCommand == null)
actionCommand = (String) defaultAction.getValue(Action.NAME);
if (actionCommand == null)
return null;
for (final JMenuItem mi : this.getMenu().getItemsAndPath(false).keySet()) {
if (actionCommand.equals(mi.getActionCommand()))
return mi;
}
return null;
}
 
// * actions
 
public final PopupBuilder addAction(Action a) {
return this.addAction(a, getDefaultGroup());
}
 
public final PopupBuilder addAction(Action a, String group) {
this.getMenu().addItem(new JMenuItem(a), group);
return this;
}
 
// * items
 
public final PopupBuilder addItem(JMenuItem mi) {
return this.addItem(mi, getDefaultGroup());
}
 
public final PopupBuilder addItem(JMenuItem mi, String group) {
this.getMenu().addItem(mi, group);
return this;
}
 
public final PopupBuilder addItemInSubmenu(JMenuItem mi, String submenu) {
return this.addItemInSubmenu(mi, getDefaultGroup(), submenu, getDefaultGroup());
}
 
public final PopupBuilder addItemInSubmenu(JMenuItem mi, String group, String submenu, String submenuGroup) {
this.getMenu().getSubmenu(submenu, group).addItem(mi, submenuGroup);
return this;
}
}
 
// never null
ButtonsBuilder getHeaderButtons();
 
/**
* The action performed if this is the {@link IListe#setDefaultRowAction(IListeAction) default}
* of an <code>IListe</code>. The returned action should have a visible feedback.
*
* @param evt the state of the <code>IListe</code>.
* @return the default action to perform, can be <code>null</code>.
*/
Action getDefaultAction(IListeEvent evt);
 
// never null
PopupBuilder getPopupContent(PopupEvent evt);
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/VirtualMenuGroup.java
New file
0,0 → 1,176
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.view.list;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
 
import javax.swing.JMenuItem;
 
/**
* A group inside a {@link VirtualMenu menu}.
*
* @author Sylvain CUAZ
*/
class VirtualMenuGroup {
 
/**
* An item inside a group.
*/
static abstract class Item {
private VirtualMenuGroup parent;
 
protected Item(final VirtualMenuGroup parent) {
this.setParentGroup(parent);
}
 
final void setParentGroup(VirtualMenuGroup parent) {
// parent can be null for the root menu, or when detached from our parent
this.parent = parent;
}
 
final VirtualMenuGroup getParentGroup() {
return this.parent;
}
 
protected abstract String getName();
 
/**
* The list of group and menu names from the root menu.
*
* @return the path to this item.
*/
abstract List<String> getPath();
 
@Override
public String toString() {
return this.getClass().getSimpleName() + " " + getName();
}
}
 
/**
* A leaf item (i.e. a {@link JMenuItem}).
*/
static class LeafItem extends Item {
private final JMenuItem mi;
 
LeafItem(final VirtualMenuGroup parent, final JMenuItem mi) {
super(parent);
this.mi = mi;
}
 
final JMenuItem getJMenuItem() {
return this.mi;
}
 
@Override
protected String getName() {
return getJMenuItem().getText();
}
 
@Override
final List<String> getPath() {
return getParentGroup().getPath();
}
}
 
private final VirtualMenu parent;
private final String name;
private final List<Item> items;
private final Map<String, VirtualMenu> menus;
 
VirtualMenuGroup(final VirtualMenu parent, final String name) {
if (parent == null)
throw new NullPointerException("Null parent");
this.parent = parent;
this.name = name;
this.items = new ArrayList<Item>();
this.menus = new LinkedHashMap<String, VirtualMenu>();
}
 
public final String getName() {
return this.name;
}
 
public final VirtualMenu getParentMenu() {
return this.parent;
}
 
public final List<String> getPath() {
final List<String> res = this.getParentMenu().getPath();
res.add(this.getName());
return res;
}
 
public final int getItemCount() {
return this.items.size();
}
 
public final List<Item> getItems() {
return Collections.unmodifiableList(this.items);
}
 
public final void add(JMenuItem mi) {
this.add(new LeafItem(this, mi));
}
 
public final void add(Item item) {
this.items.add(item);
item.setParentGroup(this);
if (item instanceof VirtualMenu) {
final VirtualMenu menu = (VirtualMenu) item;
this.menus.put(menu.getName(), menu);
}
}
 
public final void addAll(List<Item> items) {
for (final Item item : items)
this.add(item);
}
 
void merge(VirtualMenuGroup g) {
for (final Item item : g.items)
if (!(item instanceof VirtualMenu))
this.add(item);
else if (this.menus.containsKey(item.getName()))
this.menus.get(item.getName()).merge((VirtualMenu) item);
else
// avoid creating empty menu just to merge (simplify minSize/maxSize handling)
this.add(item);
}
 
public final void remove(Item item) {
this.items.remove(item);
item.setParentGroup(null);
if (item instanceof VirtualMenu) {
this.menus.remove(((VirtualMenu) item).getName());
}
}
 
protected final VirtualMenu getMenu(final String name) {
VirtualMenu res = this.menus.get(name);
if (res == null) {
res = VirtualMenu.createFromParentMenu(this, name);
this.add(res);
}
return res;
}
 
public final Map<String, VirtualMenu> getMenus() {
return Collections.unmodifiableMap(this.menus);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/RowValuesTable.java
26,6 → 26,7
import org.openconcerto.ui.table.XTableColumnModel;
import org.openconcerto.utils.checks.EmptyListener;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.Component;
import java.awt.Dimension;
404,14 → 405,14
}
 
@Override
public String getValidationText() {
public ValidState getValidState() {
if (this.model.isValidated()) {
return ValidState.getTrueInstance();
} else {
final SQLFieldTranslator trans = Configuration.getInstance().getTranslator();
return "au moins " + this.model.getSQLElement().getSingularName() + " n'a pas le champ requis \"" + trans.getLabelFor(this.model.getRequiredField()) + "\" rempli";
final String text = "au moins " + this.model.getSQLElement().getSingularName() + " n'a pas le champ requis \"" + trans.getLabelFor(this.model.getRequiredField()) + "\" rempli";
return new ValidState(false, text);
}
 
@Override
public boolean isValidated() {
return this.model.isValidated();
}
 
@Override
/trunk/OpenConcerto/src/org/openconcerto/sql/view/list/VirtualMenu.java
New file
0,0 → 1,245
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.view.list;
 
import org.openconcerto.sql.view.list.VirtualMenuGroup.Item;
import org.openconcerto.sql.view.list.VirtualMenuGroup.LeafItem;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
 
import javax.swing.Action;
import javax.swing.JMenuItem;
 
/**
* A menu containing grouped items and sub-menus.
*
* @author Sylvain CUAZ
* @see #addItem(JMenuItem, String)
* @see #getSubmenu(String, String)
*/
public class VirtualMenu extends Item {
 
public static final int MIN_SIZE = 2;
public static final int MAX_SIZE = 50;
 
static protected final VirtualMenu EMPTY = new VirtualMenu(null, null, null, 1, 1, Collections.<String, VirtualMenuGroup> emptyMap());
 
private final String name;
private final String defaultGroup;
private int minSize, maxSize;
private final Map<String, VirtualMenuGroup> groups;
 
static VirtualMenu createRoot(final String defaultGroup) {
return new VirtualMenu(null, null, defaultGroup, MIN_SIZE, MAX_SIZE);
}
 
static VirtualMenu createFromParentMenu(final VirtualMenuGroup parent, final String name) {
final VirtualMenu parentMenu = parent.getParentMenu();
return new VirtualMenu(parent, name, parentMenu.getDefaultGroupName(), parentMenu.minSize, parentMenu.maxSize);
}
 
private VirtualMenu(final VirtualMenuGroup parent, final String name, final String defaultGroup, int minSize, int maxSize) {
this(parent, name, defaultGroup, minSize, maxSize, new LinkedHashMap<String, VirtualMenuGroup>());
}
 
private VirtualMenu(final VirtualMenuGroup parent, final String name, final String defaultGroup, int minSize, int maxSize, final Map<String, VirtualMenuGroup> groups) {
super(parent);
this.name = name;
this.defaultGroup = defaultGroup;
this.setMinSize(minSize);
this.setMaxSize(maxSize);
this.groups = groups;
}
 
/**
* Set the minimum size of this menu. If this menu contains fewer items, they will be added to
* the parent menu if they have the room. The default value is {@value #MIN_SIZE}.
*
* @param minSize the new minimum size.
* @return this.
*/
public final VirtualMenu setMinSize(int minSize) {
this.minSize = minSize;
return this;
}
 
/**
* Set the maximum size of this menu. If this menu contains more items, they will be added to a
* new sub-menu. The default value is {@value #MAX_SIZE}.
*
* @param maxSize the new maximum size.
* @return this.
*/
public final VirtualMenu setMaxSize(int maxSize) {
if (maxSize < 1)
throw new IllegalArgumentException("Max size should be at least 1");
this.maxSize = maxSize;
return this;
}
 
final VirtualMenu getParentMenu() {
return this.getParentGroup().getParentMenu();
}
 
@Override
public final String getName() {
return this.name;
}
 
@Override
final List<String> getPath() {
if (this.getParentGroup() == null) {
// always return a new instance, since our callers add to the end
return new ArrayList<String>();
} else {
final List<String> res = this.getParentGroup().getPath();
res.add(getName());
assert res.size() % 2 == 0;
return res;
}
}
 
public final String getDefaultGroupName() {
return this.defaultGroup;
}
 
protected final VirtualMenuGroup getGroup(String name) {
VirtualMenuGroup res = this.groups.get(name);
if (res == null) {
res = new VirtualMenuGroup(this, name);
this.groups.put(name, res);
}
return res;
}
 
public final VirtualMenu addAction(Action a) {
return this.addItem(new JMenuItem(a));
}
 
public final VirtualMenu addItem(JMenuItem mi) {
return this.addItem(mi, getDefaultGroupName());
}
 
public final VirtualMenu addItem(JMenuItem mi, String group) {
this.getGroup(group).add(mi);
return this;
}
 
public final VirtualMenu getSubmenu(final String name) {
return this.getSubmenu(name, getDefaultGroupName());
}
 
public final VirtualMenu getSubmenu(final String name, final String group) {
return this.getGroup(group).getMenu(name);
}
 
final VirtualMenu getSubmenu(List<String> path) {
if (path.size() % 2 != 0)
throw new IllegalArgumentException("Path should be group/submenu/... :" + path);
VirtualMenu res = this;
for (int i = 0; i < path.size(); i += 2) {
res = res.getSubmenu(path.get(i + 1), path.get(i));
}
return res;
}
 
final VirtualMenu addItem(JMenuItem mi, List<String> path) {
return this.getSubmenu(path.subList(0, path.size() - 1)).addItem(mi, path.get(path.size() - 1));
}
 
final void merge(VirtualMenu m) {
for (final VirtualMenuGroup g : m.groups.values()) {
this.getGroup(g.getName()).merge(g);
}
// lessen size constraints
this.minSize = Math.min(this.minSize, m.minSize);
this.maxSize = Math.max(this.maxSize, m.maxSize);
}
 
final void applySizeConstraints() {
int size = 0;
// depth first
for (final VirtualMenuGroup g : this.groups.values()) {
for (final VirtualMenu submenu : g.getMenus().values())
submenu.applySizeConstraints();
size += g.getItemCount();
}
if (size < this.minSize) {
// if we have a parent menu with enough room
if (this.getParentGroup() != null && this.getParentMenu().hasRoomFor(size)) {
// add all items in this menu to a new group in our parent menu
final VirtualMenuGroup group = getParentMenu().getGroup(getParentGroup().getName());
for (final VirtualMenuGroup g : this.groups.values()) {
group.addAll(g.getItems());
}
this.getParentGroup().remove(this);
}
} else if (size > this.maxSize) {
final List<Item> items = new ArrayList<Item>();
for (final VirtualMenuGroup g : this.groups.values()) {
for (final Item item : g.getItems())
items.add(item);
}
assert size == items.size();
 
VirtualMenu submenu = null;
for (int i = this.maxSize; i < size; i++) {
final Item item = items.get(i);
if (i % this.maxSize == 0) {
if (this.getParentGroup() == null) {
submenu = this.getSubmenu("suite " + (i / this.maxSize), null);
} else {
submenu = this.getParentMenu().getSubmenu(getName() + " (suite " + (i / this.maxSize) + ")", getParentGroup().getName());
}
}
submenu.getGroup(item.getParentGroup().getName()).add(item);
}
}
}
 
private int getItemCount() {
int size = 0;
for (final VirtualMenuGroup g : this.groups.values()) {
size += g.getItemCount();
}
return size;
}
 
private boolean hasRoomFor(int size) {
return this.maxSize - this.getItemCount() >= size;
}
 
Map<JMenuItem, List<String>> getItemsAndPath(final boolean recurse) {
final Map<JMenuItem, List<String>> res = new LinkedHashMap<JMenuItem, List<String>>();
for (final VirtualMenuGroup g : this.groups.values()) {
for (final Item i : g.getItems())
if (i instanceof LeafItem)
res.put(((LeafItem) i).getJMenuItem(), i.getPath());
else if (recurse)
res.putAll(((VirtualMenu) i).getItemsAndPath(recurse));
}
return res;
}
 
// * getter
 
final Map<JMenuItem, List<String>> getContent() {
this.applySizeConstraints();
return this.getItemsAndPath(true);
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/SQLElementListAction.java
New file
0,0 → 1,34
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.view;
 
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.view.SQLMenuItemHelper.GenericSQLElementAction;
 
public class SQLElementListAction extends GenericSQLElementAction<IListFrame> {
private static boolean LIST_SANS_MODIF = true;
 
public static void setHasModifPanel(boolean b) {
LIST_SANS_MODIF = !b;
}
 
public SQLElementListAction(SQLElement elem) {
super(elem, "Gérer les " + elem.getPluralName());
}
 
@Override
protected IListFrame instantiateFrame() {
return new IListFrame(LIST_SANS_MODIF ? new ListeAddPanel(getElem()) : new ListeModifyPanel(getElem()));
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/view/SQLMenuItemHelper.java
15,7 → 15,6
 
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.utils.cc.IClosure;
import org.openconcerto.utils.cc.IFactory;
 
import java.awt.event.ActionEvent;
 
32,8 → 31,6
*/
public class SQLMenuItemHelper {
 
public static final SQLMenuItemHelper INSTANCE = new SQLMenuItemHelper();
 
/**
* Called for each new frame. This implementation does nothing.
*
74,10 → 71,10
* The frame that will be displayed to create an elem.
*
* @param elem the element.
* @return the frame to be displayed.
* @return the frame to be displayed, <code>null</code> to keep the default value.
*/
protected EditFrame createEditFrame(SQLElement elem) {
return new EditFrame(elem);
return null;
}
 
/**
84,10 → 81,10
* The frame that will be displayed to list an elem.
*
* @param elem the element.
* @return the frame to be displayed.
* @return the frame to be displayed, <code>null</code> to keep the default value.
*/
protected IListFrame createListFrame(SQLElement elem) {
return new IListFrame(new ListeModifyPanel(elem));
return null;
}
 
public final JMenuItem createEditMenuItem(final SQLElement elem) {
95,13 → 92,23
return new JMenuItem(createEditAction(elem));
}
 
public final SQLMenuItemAction createEditAction(final SQLElement elem) {
final SQLMenuItemAction menuItemAction = new SQLMenuItemAction(elem, "Créer " + elem.getSingularName(), new IFactory<JFrame>() {
public final SQLElementEditAction createEditAction(final SQLElement elem) {
final SQLElementEditAction menuItemAction = new SQLElementEditAction(elem) {
@Override
public JFrame createChecked() {
return ppFrame(createEditFrame(elem), null);
protected EditFrame instantiateFrame() {
final EditFrame res = createEditFrame(getElem());
if (res == null)
return super.instantiateFrame();
else
return res;
}
});
 
@Override
protected void initFrame(EditFrame f) {
super.initFrame(f);
ppFrame(f, null);
}
};
this.actionCreated(menuItemAction);
return menuItemAction;
}
115,17 → 122,27
return new JMenuItem(createListAction(elem, initFrame));
}
 
public final SQLMenuItemAction createListAction(final SQLElement elem) {
public final SQLElementListAction createListAction(final SQLElement elem) {
return this.createListAction(elem, null);
}
 
public final SQLMenuItemAction createListAction(final SQLElement elem, final IClosure<IListFrame> initFrame) {
final SQLMenuItemAction menuItemAction = new SQLMenuItemAction(elem, "Gérer les " + elem.getPluralName(), new IFactory<JFrame>() {
public final SQLElementListAction createListAction(final SQLElement elem, final IClosure<IListFrame> initFrame) {
final SQLElementListAction menuItemAction = new SQLElementListAction(elem) {
@Override
public JFrame createChecked() {
return ppFrame(createListFrame(elem), initFrame);
protected IListFrame instantiateFrame() {
final IListFrame res = createListFrame(getElem());
if (res == null)
return super.instantiateFrame();
else
return res;
}
});
 
@Override
protected void initFrame(IListFrame f) {
super.initFrame(f);
ppFrame(f, initFrame);
}
};
this.actionCreated(menuItemAction);
return menuItemAction;
}
178,21 → 195,24
}
}
 
public static class SQLMenuItemAction extends AbstractSQLMenuItemAction {
static abstract class GenericSQLElementAction<F extends JFrame> extends AbstractSQLMenuItemAction {
 
private final IFactory<? extends JFrame> frameFactory;
 
public SQLMenuItemAction(SQLElement elem, String name, IFactory<? extends JFrame> frameFactory) {
public GenericSQLElementAction(SQLElement elem, String name) {
super(elem, name);
this.frameFactory = frameFactory;
}
 
@Override
protected JFrame createFrame() {
return this.frameFactory.createChecked();
protected abstract F instantiateFrame();
 
protected void initFrame(F f) {
}
 
@Override
protected final F createFrame() {
final F res = instantiateFrame();
this.initFrame(res);
return res;
}
}
 
/**
* Ajoute "Créer" et "Gérer".
/trunk/OpenConcerto/src/org/openconcerto/sql/view/IListPanel.java
28,8 → 28,8
import org.openconcerto.sql.users.rights.UserRights;
import org.openconcerto.sql.users.rights.UserRightsManager;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.IListeAction;
import org.openconcerto.sql.view.list.ITableModel;
import org.openconcerto.sql.view.list.RowAction;
import org.openconcerto.sql.view.search.SearchListComponent;
import org.openconcerto.ui.ContinuousButtonModel;
import org.openconcerto.ui.FrameUtil;
61,6 → 61,7
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.prefs.Preferences;
 
import javax.swing.BorderFactory;
import javax.swing.Icon;
78,6 → 79,8
*/
abstract public class IListPanel extends JPanel implements ActionListener {
 
static private final String EXPORT_DIR_KEY = "exportDir";
 
static public final File getConfigFile(final SQLElement elem, final Class<? extends Container> c) {
return getConfigFile(elem, c, null);
}
155,13 → 158,11
list.setConfigFile(config);
}
this.liste = list;
final IClosure<ListChangeIndex<RowAction>> l = new IClosure<ListChangeIndex<RowAction>>() {
final IClosure<ListChangeIndex<IListeAction>> l = new IClosure<ListChangeIndex<IListeAction>>() {
@Override
public void executeChecked(ListChangeIndex<RowAction> input) {
for (final RowAction rm : input.getItemsRemoved())
getListe().removeRowAction(rm);
for (final RowAction added : input.getItemsAdded())
getListe().addRowAction(added);
public void executeChecked(ListChangeIndex<IListeAction> input) {
getListe().removeIListeActions(input.getItemsRemoved());
getListe().addIListeActions(input.getItemsAdded());
}
};
// remove listener if non displayable since getElement() never dies
169,13 → 170,11
public void hierarchyChanged(HierarchyEvent e) {
if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0)
if (isDisplayable()) {
getListe().addRowActions(getElement().getRowActions());
getListe().addRowActionFactories(getElement().getRowActionFactories());
getListe().addIListeActions(getElement().getRowActions());
getElement().addRowActionsListener(l);
} else {
getElement().removeRowActionsListener(l);
getListe().removeRowActions(getElement().getRowActions());
getListe().removeRowActionFactories(getElement().getRowActionFactories());
getListe().removeIListeActions(getElement().getRowActions());
}
}
});
480,11 → 479,14
options, options[0]);
if (answer == 0 || answer == 1) {
final FileDialog fd = new FileDialog(SwingThreadUtils.getAncestorOrSelf(Frame.class, this), "Sauver la liste", FileDialog.SAVE);
final Preferences prefs = Preferences.userNodeForPackage(this.getClass());
fd.setDirectory(prefs.get(EXPORT_DIR_KEY, Configuration.getInstance().getWD().getAbsolutePath()));
final XMLFormatVersion version = XMLFormatVersion.getDefault();
fd.setFile(this.element.getPluralName().replace('/', '-') + "." + ContentType.SPREADSHEET.getVersioned(version.getXMLVersion()).getExtension());
fd.setVisible(true);
if (fd.getFile() != null) {
final File f = this.liste.exporter(new File(fd.getDirectory(), fd.getFile()), answer == 1, version);
prefs.put(EXPORT_DIR_KEY, f.getParent());
final int i = JOptionPane.showConfirmDialog(this, "La liste est exportée au format OpenOffice classeur\n Désirez vous l'ouvrir avec OpenOffice?", "Ouvir le fichier",
JOptionPane.YES_NO_OPTION);
if (i == JOptionPane.YES_OPTION) {
/trunk/OpenConcerto/src/org/openconcerto/sql/view/EditPanel.java
15,8 → 15,8
 
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLComponent.Mode;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.SQLComponent.Mode;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowValues;
28,6 → 28,7
import org.openconcerto.utils.ExceptionHandler;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidObject;
import org.openconcerto.utils.checks.ValidState;
import org.openconcerto.utils.doc.Documented;
 
import java.awt.Container;
110,7 → 111,7
private final SQLElement element;
private IListe l;
// whether our component is valid
private boolean valid;
private ValidState valid = ValidState.getNoReasonInstance(false);
 
/**
* Creates an creation panel
173,7 → 174,7
// avant component.uiInit() car il fait un fireValidChange()
this.component.addValidListener(new ValidListener() {
@Override
public void validChange(ValidObject src, boolean newValue) {
public void validChange(ValidObject src, ValidState newValue) {
// expensive so cache it
EditPanel.this.valid = newValue;
updateBtns();
206,18 → 207,18
 
private void updateBtn(final JButton b, final boolean needValid, final boolean needID, final String desc, final String code) {
if (b != null) {
final String res;
final ValidState res;
final boolean idOK = this.getSQLComponent().getSelectedID() >= SQLRow.MIN_VALID_ID;
final UserRights rights = UserRightsManager.getCurrentUserRights();
if (!TableAllRights.hasRight(rights, code, getSQLComponent().getElement().getTable())) {
res = "Vous n'avez pas le droit " + desc;
res = ValidState.createCached(false, "Vous n'avez pas le droit " + desc);
} else if (needID && !idOK)
res = "cet élément n'existe pas";
else if (needValid && !this.valid)
res = this.component.getValidationText();
res = ValidState.createCached(false, "cet élément n'existe pas");
else if (needValid && !this.valid.isValid())
res = this.valid;
else
res = null;
updateBtn(b, res == null, res);
res = ValidState.getTrueInstance();
updateBtn(b, res);
}
}
 
437,7 → 438,7
// ne pas laisser ajouter par le raccourci clavier quand le bouton est grisé
if (this.jButtonAjouter.isEnabled()) {
final int id;
if (!Boolean.getBoolean(ADD_AT_THE_END) && this.l != null && this.l.getDesiredRow() != null)
if (!Boolean.getBoolean(ADD_AT_THE_END) && this.l != null && !this.l.isDead() && this.l.getDesiredRow() != null)
id = this.component.insert(this.l.getDesiredRow());
else
id = this.component.insert();
493,17 → 494,21
}
}
 
static void updateBtn(JButton btn, boolean valid, final String cause) {
btn.setEnabled(valid);
btn.setToolTipText(computeTooltip(valid, cause));
static void updateBtn(JButton btn, ValidState validState) {
btn.setEnabled(validState.isValid());
btn.setToolTipText(computeTooltip(validState));
}
 
static String computeTooltip(boolean valid, final String cause) {
static String computeTooltip(ValidState validState) {
return computeTooltip(validState.isValid(), validState.getValidationText());
}
 
static private String computeTooltip(boolean valid, final String cause) {
final String res;
if (valid)
res = null;
else {
final String c = cause.trim();
final String c = cause == null ? "" : cause.trim();
String validationText = "Les champs de saisie ne sont pas remplis correctement.\n\nVous ne pouvez enregistrer les modifications car";
if (c.length() > 0)
validationText += "\n" + c;
/trunk/OpenConcerto/src/org/openconcerto/sql/view/ListeModifyPanel.java
17,12 → 17,13
package org.openconcerto.sql.view;
 
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.SQLComponent.Mode;
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.element.SQLComponent.Mode;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.utils.cc.ITransformer;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidObject;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.Container;
import java.awt.Dimension;
41,7 → 42,7
private SQLComponent modifComp;
// le scrollPane qui contient modifComp
private JScrollPane scrollPane;
private String validText = null;
private ValidState compValidity = ValidState.getTrueInstance();
 
public ListeModifyPanel(SQLElement elem) {
super(elem);
72,7 → 73,7
this.btnMngr.setAdditional(this.buttonModifier, new ITransformer<JButton, String>() {
@Override
public String transformChecked(JButton input) {
return EditPanel.computeTooltip(ListeModifyPanel.this.validText == null, ListeModifyPanel.this.validText);
return EditPanel.computeTooltip(ListeModifyPanel.this.compValidity);
}
});
 
107,7 → 108,7
// force buttonModifier update because the super method enables it
// if a line is selected, then we select the new id, but if the new line
// has the same empty fields than the previous one, no validChange is fired
this.validChange(this.getModifComp(), this.getModifComp().isValidated());
this.validChange(this.getModifComp(), this.getModifComp().getValidState());
this.getModifComp().setEditable(id != -1);
// have to invokeLater() since the scrollbar is changed after this method return
// eg DefaultCaret.changeCaretPosition() -- caused by this.modifComp.select(id) -- will
122,9 → 123,10
/*
* notre comp de modif à changé d'état
*/
public void validChange(ValidObject src, boolean newValue) {
@Override
public void validChange(ValidObject src, ValidState newValue) {
// MAYBE add a isAdjusting while changing id
this.validText = newValue ? null : this.getModifComp().getValidationText();
this.compValidity = newValue;
this.btnMngr.updateBtn(this.buttonModifier);
}
 
/trunk/OpenConcerto/src/org/openconcerto/sql/view/SQLElementEditAction.java
New file
0,0 → 1,29
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.sql.view;
 
import org.openconcerto.sql.element.SQLElement;
import org.openconcerto.sql.view.SQLMenuItemHelper.GenericSQLElementAction;
 
public class SQLElementEditAction extends GenericSQLElementAction<EditFrame> {
 
public SQLElementEditAction(SQLElement elem) {
super(elem, "Créer " + elem.getSingularName());
}
 
@Override
protected EditFrame instantiateFrame() {
return new EditFrame(getElem());
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/PropsConfiguration.java
63,8 → 63,8
 
import org.apache.commons.collections.Predicate;
 
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.LocalPortForwarder;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
 
/**
* A configuration which takes its values primarily from Properties. You should also subclass its
167,8 → 167,7
private final List<Configuration> translationsToAdd;
 
// SSL
private Connection conn;
private LocalPortForwarder lpf;
private Session conn;
private boolean isUsingSSH;
 
public PropsConfiguration() throws IOException {
340,17 → 339,16
}
assert origExn != null;
}
this.conn = new Connection(wanAddr, Integer.valueOf(wanPort));
this.openSSLConnection();
this.openSSLConnection(wanAddr, Integer.valueOf(wanPort));
this.isUsingSSH = true;
log.info("ssl connection to " + this.conn.getHostname() + ":" + this.conn.getPort());
log.info("ssl connection to " + this.conn.getHost() + ":" + this.conn.getPort());
final int localPort = 5436;
try {
// TODO add and use server.port
final String[] serverAndPort = getProperty("server.ip").split(":");
log.info("ssl tunnel from local port " + localPort + " to remote " + serverAndPort[0] + ":" + serverAndPort[1]);
this.lpf = this.conn.createLocalPortForwarder(localPort, serverAndPort[0], Integer.valueOf(serverAndPort[1]));
} catch (IOException e1) {
this.conn.setPortForwardingL(localPort, serverAndPort[0], Integer.valueOf(serverAndPort[1]));
} catch (Exception e1) {
throw new IllegalStateException("Impossible de créer la liaison sécurisée. Vérifier que le logiciel n'est pas déjà lancé.", e1);
}
setProperty("server.ip", "localhost:" + localPort);
381,12 → 379,12
});
}
 
private void openSSLConnection() {
private void openSSLConnection(String addr, int port) {
final String username = getSSLUserName();
boolean isAuthenticated = false;
 
final JSch jsch = new JSch();
try {
// wait no more than 6 seconds for TCP connection
this.conn.connect(null, 6000, 12000);
final ByteArrayOutputStream out = new ByteArrayOutputStream(700);
final String name = username + "_dsa";
final InputStream in = getClass().getResourceAsStream(name);
394,7 → 392,20
throw new IllegalStateException("Missing private key " + getClass().getCanonicalName() + "/" + name);
StreamUtils.copy(in, out);
in.close();
isAuthenticated = this.conn.authenticateWithPublicKey(username, out.toString("UTF-8").toCharArray(), null);
jsch.addIdentity(username, out.toByteArray(), null, null);
 
this.conn = jsch.getSession(username, addr, port);
final Properties config = new Properties();
// Set StrictHostKeyChecking property to no to avoid UnknownHostKey issue
config.put("StrictHostKeyChecking", "no");
// *2 gain
config.put("compression.s2c", "zlib@openssh.com,zlib,none");
config.put("compression.c2s", "zlib@openssh.com,zlib,none");
this.conn.setConfig(config);
// wait no more than 6 seconds for TCP connection
this.conn.connect(6000);
 
isAuthenticated = true;
} catch (Exception e) {
throw new IllegalStateException("Connection failed", e);
}
407,16 → 418,8
}
 
private void closeSSLConnection() {
if (this.lpf != null)
try {
this.lpf.close();
this.lpf = null;
} catch (IOException e) {
// tant pis
e.printStackTrace();
}
if (this.conn != null) {
this.conn.close();
this.conn.disconnect();
this.conn = null;
}
}
/trunk/OpenConcerto/src/org/openconcerto/sql/ui/ConnexionPanel.java
311,7 → 311,7
if (this.textLogin == null || this.textLogin.isEmpty() || this.textPassWord == null) {
return false;
} else {
return this.textLogin.isValidated();
return this.textLogin.getValidState().isValid();
}
}
 
/trunk/OpenConcerto/src/org/openconcerto/utils/GestionDevise.java
140,6 → 140,20
return DECIMAL_FORMAT.format(currency);
}
 
public final static String round(long cents) {
if (cents == 0) {
return "0";
}
 
final long truncated = cents / 100;
final long rounded;
if (cents % 100 >= 50)
rounded = truncated + 1;
else
rounded = truncated;
return String.valueOf(rounded);
}
 
/**
*
* @param cents long representant des cents
/trunk/OpenConcerto/src/org/openconcerto/utils/StringUtils.java
237,7 → 237,7
char charAt = s.charAt(i);
if (charAt == '\n') {
lastString.append(charAt);
result.append(charAt);
result.append(lastString);
lastString = new StringBuffer();
} else {
 
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/IPredicate.java
23,6 → 23,12
return true;
}
};
private static final IPredicate<Object> falsePred = new IPredicate<Object>() {
@Override
public boolean evaluateChecked(Object input) {
return false;
}
};
private static final IPredicate<Object> NotNullPred = new IPredicate<Object>() {
@Override
public boolean evaluateChecked(Object input) {
36,6 → 42,11
}
 
@SuppressWarnings("unchecked")
public static final <N> IPredicate<N> falsePredicate() {
return (IPredicate<N>) falsePred;
}
 
@SuppressWarnings("unchecked")
public static final <N> IPredicate<N> notNullPredicate() {
return (IPredicate<N>) NotNullPred;
}
47,4 → 58,70
 
public abstract boolean evaluateChecked(E input);
 
public final <F extends E> IPredicate<F> cast() {
// this class never returns E, only takes it as argument
// but we cannot return this instance :
// class Sub<E> extends IPredicate<E> {
// E someMethod();
// }
// Sub<Number> n;
// IPredicate<Integer> cast = n.<Integer> cast();
// Sub<Integer> n2 = (Sub<Integer>) cast;
// the cast in the line above will succeed but n2.someMethod()
// will fail if n.someMethod() returns a BigDecimal
 
// since we're returning a new IPredicate instance, the n2 line would correctly fail
return new IPredicate<F>() {
@Override
public boolean evaluateChecked(F input) {
return IPredicate.this.evaluateChecked(input);
}
};
}
 
public final IPredicate<E> not() {
if (this == truePred)
return falsePredicate();
else if (this == falsePred)
return truePredicate();
else
return new IPredicate<E>() {
@Override
public boolean evaluateChecked(E input) {
return !IPredicate.this.evaluateChecked(input);
}
};
}
 
public final IPredicate<E> and(final IPredicate<? super E> o) {
if (o == this || o == truePred)
return this;
else if (this == truePred)
return o.cast();
else if (o == falsePred || this == falsePred)
return falsePredicate();
else
return new IPredicate<E>() {
@Override
public boolean evaluateChecked(E input) {
return IPredicate.this.evaluateChecked(input) && o.evaluateChecked(input);
}
};
}
 
public final IPredicate<E> or(final IPredicate<? super E> o) {
if (o == this || o == falsePred)
return this;
else if (this == falsePred)
return o.cast();
else if (o == truePred || this == truePred)
return truePredicate();
else
return new IPredicate<E>() {
@Override
public boolean evaluateChecked(E input) {
return IPredicate.this.evaluateChecked(input) || o.evaluateChecked(input);
}
};
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/cc/ConstantFactory.java
22,6 → 22,15
return (ConstantFactory<F>) nullFactory;
}
 
static public final <E, F> ITransformer<E, F> createTransformer(final F obj) {
return new ITransformer<E, F>() {
@Override
public F transformChecked(E input) {
return obj;
}
};
}
 
private final E obj;
 
public ConstantFactory(E obj) {
/trunk/OpenConcerto/src/org/openconcerto/utils/NumberUtils.java
13,6 → 13,8
package org.openconcerto.utils;
 
import org.openconcerto.utils.convertor.NumberConvertor;
 
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.concurrent.atomic.AtomicInteger;
21,6 → 23,123
public class NumberUtils {
 
/**
* Test class and numerical equality. E.g. {@link BigDecimal#equals(Object)} also tests the
* scale.
*
* @param <N> type of number.
* @param n1 first number, can be <code>null</code>.
* @param n2 second number, can be <code>null</code>.
* @return <code>true</code> if <code>n1</code> and <code>n2</code> have the same class and are
* numerically equal.
* @see #areNumericallyEqual(Number, Number)
*/
static public final <N extends Number> boolean areEqual(final N n1, final N n2) {
if (n1 == null && n2 == null)
return true;
if (n1 == null || n2 == null)
return false;
final Class<? extends Number> n1Class = n1.getClass();
if (n1Class != n2.getClass())
return false;
// Atomic* don't implement equals()
if (n1Class == AtomicInteger.class || n1Class == AtomicLong.class)
return n1.longValue() == n2.longValue();
else if (n1Class == BigDecimal.class)
return ((BigDecimal) n1).compareTo((BigDecimal) n2) == 0;
else
return n1.equals(n2);
}
 
/**
* Test numerical equality (but ignore class).
*
* @param n1 first number, can be <code>null</code>.
* @param n2 second number, can be <code>null</code>.
* @return <code>true</code> if <code>n1</code> and <code>n2</code> are numerically equal.
* @see #compare(Number, Number)
*/
static public final boolean areNumericallyEqual(final Number n1, final Number n2) {
if (n1 == null && n2 == null)
return true;
if (n1 == null || n2 == null)
return false;
return compare(n1, n2) == 0;
}
 
/**
* Compare two arbitrary numbers.
*
* @param n1 first number, not <code>null</code>.
* @param n2 second number, not <code>null</code>.
* @return a negative integer, zero, or a positive integer as n1 is less than, equal to, or
* greater than n2.
* @see Comparable#compareTo(Object)
*/
static public final int compare(final Number n1, final Number n2) {
Class<? extends Number> biggerClass = getWiderClass(n1, n2);
// Atomic* aren't Comparable
if (biggerClass == AtomicInteger.class)
biggerClass = Integer.class;
else if (biggerClass == AtomicLong.class)
biggerClass = Long.class;
return compare(n1, n2, biggerClass);
}
 
static private final <N extends Number> int compare(final Number n1, final Number n2, Class<N> clazz) {
final N n1Converted = NumberConvertor.convertExact(n1, clazz);
final N n2Converted = NumberConvertor.convertExact(n2, clazz);
@SuppressWarnings("unchecked")
final Comparable<N> comparable = (Comparable<N>) n1Converted;
return comparable.compareTo(n2Converted);
}
 
/**
* Return a class wide enough for both numbers. E.g. for Integer and Short, Integer ; for
* BigInteger and Float, BigDecimal.
*
* @param n1 first number, not <code>null</code>.
* @param n2 second number, not <code>null</code>.
* @return a class wide enough for both numbers.
* @see NumberConvertor#convertExact(Number, Class)
*/
static public final Class<? extends Number> getWiderClass(final Number n1, final Number n2) {
final Class<? extends Number> n1Class = n1.getClass();
final Class<? extends Number> n2Class = n2.getClass();
if (n1Class == n2Class)
return n1Class;
if (n1Class == BigDecimal.class || n2Class == BigDecimal.class)
return BigDecimal.class;
 
final boolean n1isFloat = n1Class == Float.class || n1Class == Double.class;
final boolean n2isFloat = n2Class == Float.class || n2Class == Double.class;
if (n1isFloat && n2isFloat) {
// since classes are different, at least one is Double
return Double.class;
} else if (n1isFloat || n2isFloat) {
// the only class (except the already handled BigDecimal) that can overflow in a Double
// is BigInteger
if (n1Class == BigInteger.class || n2Class == BigInteger.class)
return BigDecimal.class;
else
return Double.class;
}
 
// integers or BigInteger
if (n1Class == BigInteger.class || n2Class == BigInteger.class)
return BigInteger.class;
else if (n1Class == Long.class || n2Class == Long.class || n1Class == AtomicLong.class || n2Class == AtomicLong.class)
return Long.class;
else if (n1Class == Integer.class || n2Class == Integer.class || n1Class == AtomicInteger.class || n2Class == AtomicInteger.class)
return Integer.class;
else if (n1Class == Short.class || n2Class == Short.class)
return Short.class;
else if (n1Class == Byte.class || n2Class == Byte.class)
return Byte.class;
else
throw new IllegalStateException("Unknown classes " + n1Class + " / " + n2Class);
}
 
/**
* Whether <code>n</code> has a non-zero fractional part.
*
* @param n a number.
/trunk/OpenConcerto/src/org/openconcerto/utils/convertor/NumberConvertor.java
13,6 → 13,11
package org.openconcerto.utils.convertor;
 
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
 
public abstract class NumberConvertor<T extends Number, U extends Number> implements ValueConvertor<T, U> {
 
public static final NumberConvertor<Integer, Long> INT_TO_LONG = new NumberConvertor<Integer, Long>() {
39,6 → 44,20
}
};
 
public static final <N1 extends Number, N2 extends Number> NumberConvertor<N1, N2> create(final Class<N1> c1, final Class<N2> c2, final boolean exact) {
return new NumberConvertor<N1, N2>() {
@Override
public N2 convert(N1 o) {
return exact ? convertExact(o, c2) : convert(o, c2);
}
 
@Override
public N1 unconvert(N2 o) {
return exact ? convertExact(o, c1) : convert(o, c1);
}
};
}
 
/**
* Convert from one class of {@link Number} to another. Necessary since new Integer(123) isn't
* equal to new Long(123).
50,7 → 69,7
*/
public static <N extends Number> N convert(Number n, Class<N> clazz) {
final Number res;
if (n.getClass() == clazz) {
if (n == null || n.getClass() == clazz || clazz == Number.class) {
res = n;
} else if (clazz == Short.class) {
res = n.shortValue();
60,6 → 79,21
res = n.longValue();
} else if (clazz == Byte.class) {
res = n.byteValue();
} else if (clazz == BigInteger.class) {
if (n instanceof BigDecimal)
res = ((BigDecimal) n).toBigInteger();
else if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong)
res = BigInteger.valueOf(n.longValue());
else if (n instanceof Float || n instanceof Double)
res = BigDecimal.valueOf(n.doubleValue()).toBigInteger();
else
res = new BigInteger(n.toString());
} else if (clazz == AtomicInteger.class) {
res = new AtomicInteger(n.intValue());
} else if (clazz == AtomicLong.class) {
res = new AtomicLong(n.longValue());
} else if (clazz == BigDecimal.class) {
res = toBigDecimal(n);
} else if (clazz == Double.class) {
res = n.doubleValue();
} else if (clazz == Float.class) {
69,4 → 103,191
}
return clazz.cast(res);
}
 
public static BigDecimal toBigDecimal(final Number n) {
final BigDecimal res;
if (n == null || n instanceof BigDecimal) {
res = (BigDecimal) n;
} else if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong) {
res = BigDecimal.valueOf(n.longValue());
} else if (n instanceof Float || n instanceof Double) {
res = BigDecimal.valueOf(n.doubleValue());
} else if (n instanceof BigInteger) {
res = new BigDecimal((BigInteger) n);
} else {
res = new BigDecimal(n.toString());
}
return res;
}
 
public static class OverflowException extends ArithmeticException {
public OverflowException(Number n, Class<? extends Number> clazz) {
super("Cannot convert to " + clazz + " : " + n);
}
 
@Override
public OverflowException initCause(Throwable cause) {
super.initCause(cause);
return this;
}
}
 
public static class RoundingException extends ArithmeticException {
public RoundingException(Number n, Class<? extends Number> clazz) {
super("Rounding necessary for " + clazz + " : " + n + " (" + n.getClass() + ")");
}
}
 
public static final BigDecimal MAX_FLOAT = BigDecimal.valueOf(Float.MAX_VALUE);
public static final BigDecimal MIN_FLOAT = MAX_FLOAT.negate();
public static final BigDecimal MAX_DOUBLE = BigDecimal.valueOf(Double.MAX_VALUE);
public static final BigDecimal MIN_DOUBLE = MAX_DOUBLE.negate();
 
public static <N extends Number> N convertExact(Number n, Class<N> clazz) throws OverflowException, RoundingException {
final Number res;
if (n == null || n.getClass() == clazz || clazz == Number.class) {
res = n;
} else if (n instanceof BigDecimal) {
// cannot use *ValueExact() since we want to differentiate between overflow and rounding
final BigDecimal bd = (BigDecimal) n;
if (clazz == Byte.class || clazz == Short.class || clazz == Integer.class || clazz == AtomicInteger.class || clazz == Long.class || clazz == AtomicLong.class || clazz == BigInteger.class) {
final BigInteger bi;
try {
bi = bd.toBigIntegerExact();
} catch (ArithmeticException e) {
throw new RoundingException(n, clazz);
}
if (clazz == BigInteger.class) {
res = bi;
} else {
try {
res = convertExact(bi, clazz);
} catch (RoundingException e) {
// cannot be a rounding error since we pass a BigInteger
throw new IllegalStateException(e);
} catch (OverflowException e) {
throw new OverflowException(n, clazz).initCause(e);
}
}
} else if (clazz == Float.class) {
if (bd.compareTo(MAX_FLOAT) > 0 || bd.compareTo(MIN_FLOAT) < 0)
throw new OverflowException(n, clazz);
res = n.floatValue();
} else if (clazz == Double.class) {
if (bd.compareTo(MAX_DOUBLE) > 0 || bd.compareTo(MIN_DOUBLE) < 0)
throw new OverflowException(n, clazz);
res = n.doubleValue();
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
} else if (clazz == Byte.class) {
final byte value = n.byteValue();
if (n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong) {
if (value != n.longValue())
throw new OverflowException(n, clazz);
} else if (n instanceof BigInteger) {
if (((BigInteger) n).bitLength() >= Byte.SIZE)
throw new OverflowException(n, clazz);
} else if (n instanceof Float || n instanceof Double) {
if (n.doubleValue() > Byte.MAX_VALUE || n.doubleValue() < Byte.MIN_VALUE)
throw new OverflowException(n, clazz);
else
throw new RoundingException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = value;
} else if (clazz == Short.class) {
final short value = n.shortValue();
if (n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong) {
if (value != n.longValue())
throw new OverflowException(n, clazz);
} else if (n instanceof Byte) {
} else if (n instanceof BigInteger) {
if (((BigInteger) n).bitLength() >= Short.SIZE)
throw new OverflowException(n, clazz);
} else if (n instanceof Float || n instanceof Double) {
if (n.doubleValue() > Short.MAX_VALUE || n.doubleValue() < Short.MIN_VALUE)
throw new OverflowException(n, clazz);
else
throw new RoundingException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = value;
} else if (clazz == Integer.class || clazz == AtomicInteger.class) {
final int value = n.intValue();
if (n instanceof Long || n instanceof AtomicLong) {
if (value != n.longValue())
throw new OverflowException(n, clazz);
} else if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger) {
} else if (n instanceof BigInteger) {
if (((BigInteger) n).bitLength() >= Integer.SIZE)
throw new OverflowException(n, clazz);
} else if (n instanceof Float || n instanceof Double) {
if (n.doubleValue() > Integer.MAX_VALUE || n.doubleValue() < Integer.MIN_VALUE)
throw new OverflowException(n, clazz);
else
throw new RoundingException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = clazz == Integer.class ? Integer.valueOf(value) : new AtomicInteger(value);
} else if (clazz == Long.class || clazz == AtomicLong.class) {
final long value = n.longValue();
if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong) {
} else if (n instanceof BigInteger) {
if (((BigInteger) n).bitLength() >= Long.SIZE)
throw new OverflowException(n, clazz);
} else if (n instanceof Float || n instanceof Double) {
// at the limits of Long, Double have less than one unit of precision, so since both
// case of this if throw exceptions, be lenient to allow testing the limits
if (n.doubleValue() >= Long.MAX_VALUE || n.doubleValue() <= Long.MIN_VALUE)
throw new OverflowException(n, clazz);
else
throw new RoundingException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = clazz == Long.class ? Long.valueOf(value) : new AtomicLong(value);
} else if (clazz == BigInteger.class) {
if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong) {
} else if (n instanceof Float || n instanceof Double) {
throw new RoundingException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = BigInteger.valueOf(n.longValue());
} else if (clazz == BigDecimal.class) {
res = toBigDecimal(n);
} else if (clazz == Double.class) {
if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong || n instanceof Float) {
} else if (n instanceof BigInteger) {
final BigInteger bi = (BigInteger) n;
// can use toBigIntegerExact() since the precision is low at the limits
if (bi.compareTo(MAX_DOUBLE.toBigIntegerExact()) > 0 || bi.compareTo(MIN_DOUBLE.toBigIntegerExact()) < 0)
throw new OverflowException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = n.doubleValue();
} else if (clazz == Float.class) {
if (n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof AtomicInteger || n instanceof Long || n instanceof AtomicLong) {
} else if (n instanceof Double) {
if (Math.abs(n.doubleValue()) > Float.MAX_VALUE)
throw new OverflowException(n, clazz);
} else if (n instanceof BigInteger) {
final BigInteger bi = (BigInteger) n;
// can use toBigIntegerExact() since the precision is low at the limits
if (bi.compareTo(MAX_FLOAT.toBigIntegerExact()) > 0 || bi.compareTo(MIN_FLOAT.toBigIntegerExact()) < 0)
throw new OverflowException(n, clazz);
} else {
throw new IllegalStateException("Unknown class " + n.getClass());
}
res = n.floatValue();
} else {
throw new IllegalArgumentException("Unknown class: " + clazz);
}
return clazz.cast(res);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/convertor/ValueConvertorFactory.java
20,6 → 20,24
 
public final class ValueConvertorFactory {
 
@SuppressWarnings("rawtypes")
private static final ValueConvertor IdentityConvertor = new ValueConvertor() {
@Override
public Object convert(Object o) {
return o;
}
 
@Override
public Object unconvert(Object o) {
return o;
}
};
 
@SuppressWarnings("unchecked")
public static final <T> ValueConvertor<T, T> getIdentityConvertor() {
return (ValueConvertor<T, T>) IdentityConvertor;
}
 
private static final List<ValueConvertor<?, ?>> convs;
static {
convs = new ArrayList<ValueConvertor<?, ?>>();
26,10 → 44,14
convs.add(new DateTSConvertor());
convs.add(new DateToTimeConvertor());
convs.add(StringClobConvertor.INSTANCE);
convs.add(NumberConvertor.INT_TO_LONG);
convs.add(NumberConvertor.SHORT_TO_INT);
}
 
@SuppressWarnings("unchecked")
public static final <T, U> ValueConvertor<T, U> find(Class<T> c1, Class<U> c2) {
if (c1 == c2)
return (ValueConvertor<T, U>) getIdentityConvertor();
for (final ValueConvertor<?, ?> vc : convs) {
final List<Class<?>> args = ReflectUtils.getTypeArguments(vc, ValueConvertor.class);
if (args.size() != 2)
40,6 → 62,9
return new ReverseConvertor<T, U>((ValueConvertor<U, T>) vc);
}
}
if (Number.class.isAssignableFrom(c1) && Number.class.isAssignableFrom(c2))
return (ValueConvertor<T, U>) NumberConvertor.create(c1.asSubclass(Number.class), c2.asSubclass(Number.class), true);
 
return null;
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/text/FixedWidthOuputer.java
New file
0,0 → 1,87
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.text;
 
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
 
public class FixedWidthOuputer {
private final PrintStream stream;
private final String lineDelimiter;
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
private final String encoding;
private int lineCount = 0;
 
public FixedWidthOuputer(String encoding, String lineDelimiter) throws UnsupportedEncodingException {
this.lineDelimiter = lineDelimiter;
this.encoding = encoding;
stream = new PrintStream(out, false, encoding);
}
 
public void addLine() {
lineCount = 0;
stream.append(lineDelimiter);
}
 
public String getContent() {
try {
return out.toString(encoding);
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException(e);
}
}
 
public void addSpace(int n) {
for (int i = 0; i < n; i++) {
stream.append(' ');
}
lineCount += n;
}
 
public void add(String string, int size) {
addLeft(string, size, ' ');
 
}
 
private void addLeft(String string, int size, char c) {
final int length = string.length();
for (int i = 0; i < size; i++) {
if (i < length) {
stream.append(string.charAt(i));
} else {
stream.append(c);
}
}
lineCount += size;
}
 
public void addRight(String string, int size, char c) {
 
final int length = string.length();
for (int i = 0; i < size; i++) {
if (i >= size - length) {
stream.append(string.charAt(i - size + length));
} else {
stream.append(c);
}
}
lineCount += size;
}
 
public int getLineCount() {
return lineCount;
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/checks/ValidListener.java
24,6 → 24,6
*/
public interface ValidListener {
 
public void validChange(ValidObject src, boolean newValue);
public void validChange(ValidObject src, ValidState newValue);
 
}
/trunk/OpenConcerto/src/org/openconcerto/utils/checks/ValidObjectCombiner.java
13,8 → 13,6
package org.openconcerto.utils.checks;
 
import org.openconcerto.utils.CollectionUtils;
 
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
50,7 → 48,7
 
for (final ValidObject o : this.objects) {
o.addValidListener(new ValidListener() {
public void validChange(ValidObject src, boolean newValue) {
public void validChange(ValidObject src, ValidState newValue) {
validChanged();
}
});
58,26 → 56,18
}
 
protected final void validChanged() {
this.supp.fireValidChange(this.isValidated());
this.supp.fireValidChange(this.getValidState());
}
 
public final boolean isValidated() {
boolean res = true;
@Override
public ValidState getValidState() {
ValidState res = ValidState.getTrueInstance();
for (final ValidObject o : this.objects) {
res = res && o.isValidated();
res = res.and(o.getValidState(), " ; ");
}
return res;
}
 
public String getValidationText() {
final List<String> res = new ArrayList<String>();
for (final ValidObject o : this.objects) {
if (!o.isValidated())
res.add(o.getValidationText());
}
return CollectionUtils.join(res, " ; ");
}
 
public void addValidListener(ValidListener l) {
this.supp.addValidListener(l);
}
/trunk/OpenConcerto/src/org/openconcerto/utils/checks/ValidObject.java
13,7 → 13,6
/*
* Créé le 3 févr. 2005
*
*/
package org.openconcerto.utils.checks;
 
24,16 → 23,9
*/
public interface ValidObject {
 
public boolean isValidated();
public ValidState getValidState();
 
public void addValidListener(ValidListener l);
public void removeValidListener(ValidListener l);
 
/**
* Why isValidated() returns its value.
*
* @return an explanation, eg "value is negative", can be <code>null</code>.
*/
public String getValidationText();
}
/trunk/OpenConcerto/src/org/openconcerto/utils/checks/ChainValidListener.java
31,7 → 31,8
this.delegate = delegate;
}
 
public void validChange(ValidObject src, boolean newValue) {
@Override
public void validChange(ValidObject src, ValidState newValue) {
this.delegate.validChange(this.target, newValue);
}
 
/trunk/OpenConcerto/src/org/openconcerto/utils/checks/ValidState.java
New file
0,0 → 1,169
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.utils.checks;
 
import org.openconcerto.utils.CompareUtils;
 
import java.util.LinkedHashMap;
import java.util.Map;
 
public class ValidState {
 
static private final ValidState TRUE = new ValidState(true, null);
static private final ValidState FALSE = new ValidState(false, null);
static private final Map<String, ValidState> cache = new LinkedHashMap<String, ValidState>(32, 0.75f, true) {
@Override
protected boolean removeEldestEntry(java.util.Map.Entry<String, ValidState> eldest) {
return this.size() > 50;
}
};
 
static public final ValidState getTrueInstance() {
return TRUE;
}
 
static public final ValidState getNoReasonInstance(final boolean isValid) {
return isValid ? TRUE : FALSE;
}
 
/**
* Only create an instance if necessary. This method only caches instances without reason, so it
* can be used if the reason is not a constant so as not to pollute the cache :
* <code>ValidState.create(!clientExists, "Client '" + name + "' already exists")</code>
*
* @param valid the validity.
* @param invalidityReason the reason that valid is <code>false</code>.
* @return a new instance if needed (e.g. if valid is <code>true</code> will return
* {@link #getTrueInstance()}).
* @see #createCached(boolean, String)
*/
static public final ValidState create(boolean valid, String reason) {
return create(valid, reason, false);
}
 
/**
* Only create an instance if necessary. This method caches all instances, so it should be used
* if reason is a constant :
* <code>ValidState.createCached(!clientExists, "Client already exists")</code>. Of course if
* reason is a constant you can get better performance by creating a constant instead of relying
* on a non-deterministic cache.
*
* @param valid the validity.
* @param invalidityReason the reason that valid is <code>false</code>.
* @return a new instance if not already cached.
* @see #create(boolean, String)
*/
static public final ValidState createCached(boolean valid, String reason) {
return create(valid, reason, true);
}
 
static public final ValidState create(boolean valid, String reason, final boolean cacheNonValid) {
if (valid) {
return TRUE;
} else if (reason == null) {
return FALSE;
} else if (cacheNonValid) {
ValidState res = cache.get(reason);
if (res == null) {
res = new ValidState(valid, reason);
cache.put(reason, res);
}
return res;
} else {
return new ValidState(valid, reason);
}
}
 
static public final ValidState createInvalid(String reason) {
// to cache use createCached(false, reason)
return new ValidState(false, reason);
}
 
private final boolean valid;
private final String reason;
 
/**
* Create a new instance.
*
* @param valid the validity.
* @param invalidityReason the reason that valid is <code>false</code>, ignored if valid is
* <code>true</code>.
* @see #create(boolean, String)
*/
public ValidState(boolean valid, String invalidityReason) {
this.valid = valid;
this.reason = valid ? null : invalidityReason;
}
 
public final boolean isValid() {
return this.valid;
}
 
/**
* Why {@link #isValid()} is <code>false</code> (always <code>null</code> if <code>true</code>).
*
* @return an explanation, e.g. "value is negative", can be <code>null</code>.
*/
public final String getValidationText() {
return this.reason;
}
 
private final boolean validationTextIsEmpty() {
return this.reason == null || this.reason.trim().length() == 0;
}
 
public ValidState and(ValidState other) {
return this.and(other, "\n");
}
 
public ValidState and(ValidState other, final String sep) {
if (this.equals(other))
return this;
else if (this.equals(TRUE))
return other;
else if (other.equals(TRUE))
return this;
final String reason;
if (CompareUtils.equals(this.getValidationText(), other.getValidationText()))
reason = this.getValidationText();
else if (this.validationTextIsEmpty())
reason = other.getValidationText();
else if (other.validationTextIsEmpty())
reason = this.getValidationText();
else
reason = this.getValidationText() + sep + other.getValidationText();
return new ValidState(this.isValid() && other.isValid(), reason);
}
 
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.reason == null) ? 0 : this.reason.hashCode());
result = prime * result + (this.valid ? 1231 : 1237);
return result;
}
 
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final ValidState other = (ValidState) obj;
return this.valid == other.valid && CompareUtils.equals(this.reason, other.reason);
}
}
/trunk/OpenConcerto/src/org/openconcerto/utils/checks/ValidChangeSupport.java
20,13 → 20,13
 
private final ValidObject target;
private final List<ValidListener> listeners;
private Boolean validState;
private ValidState validState;
 
public ValidChangeSupport(final ValidObject target) {
this(target, null);
}
 
public ValidChangeSupport(final ValidObject target, final Boolean initialState) {
public ValidChangeSupport(final ValidObject target, final ValidState initialState) {
super();
if (target == null)
throw new NullPointerException("null target");
36,11 → 36,11
this.validState = initialState;
}
 
public final Boolean getValidState() {
public final ValidState getValidState() {
return this.validState;
}
 
public final void fireValidChange(final Boolean newValue) {
public final void fireValidChange(final ValidState newValue) {
if (!newValue.equals(this.validState)) {
this.validState = newValue;
for (final ValidListener l : this.listeners) {
/trunk/OpenConcerto/src/org/openconcerto/task/TodoListPanel.java
29,11 → 29,11
import org.openconcerto.ui.table.AlternateTableCellRenderer;
import org.openconcerto.ui.table.IconTableCellRenderer;
import org.openconcerto.ui.table.JCheckBoxTableCellRender;
import org.openconcerto.ui.table.PopUpTableManager;
import org.openconcerto.ui.table.TablePopupMenuProvider;
import org.openconcerto.ui.table.TablePopupMouseListener;
import org.openconcerto.ui.table.TimestampTableCellEditor;
import org.openconcerto.ui.table.TimestampTableCellRenderer;
import org.openconcerto.utils.TableSorter;
import org.openconcerto.utils.cc.ITransformer;
 
import java.awt.Color;
import java.awt.Component;
72,6 → 72,7
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
83,6 → 84,7
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
90,8 → 92,6
 
import org.apache.commons.dbutils.ResultSetHandler;
 
import javax.swing.table.DefaultTableCellRenderer;
 
public class TodoListPanel extends JPanel implements ModelStateListener {
 
// Actions
510,15 → 510,18
}
 
void initPopUp() {
new PopUpTableManager(this.t, new TablePopupMenuProvider() {
TablePopupMouseListener.add(this.t, new ITransformer<MouseEvent, JPopupMenu>() {
 
public List getActions(final JTable table, final int row) {
List<Action> v = new Vector<Action>(3);
@Override
public JPopupMenu transformChecked(MouseEvent evt) {
final JTable table = (JTable) evt.getSource();
final int modelIndex = TodoListPanel.this.sorter.modelIndex(table.getSelectedRow());
final JPopupMenu res = new JPopupMenu();
 
// Avancer d'un jour
Action act = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
final TodoListElement element = TodoListPanel.this.model.getTaskAtRow(TodoListPanel.this.sorter.modelIndex(row));
final TodoListElement element = TodoListPanel.this.model.getTaskAtRow(modelIndex);
if (element != null) {
final Date ts = element.getExpectedDate();
final Calendar cal = Calendar.getInstance();
536,12 → 539,12
}
};
act.putValue(Action.NAME, "Avancer d'un jour");
v.add(act);
res.add(act);
 
// Marquer comme réalisé
act = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
TodoListElement element = TodoListPanel.this.model.getTaskAtRow(TodoListPanel.this.sorter.modelIndex(row));
TodoListElement element = TodoListPanel.this.model.getTaskAtRow(modelIndex);
if (element != null) {
element.setDone(true);
element.commitChangesAndWait();
550,28 → 553,28
}
};
act.putValue(Action.NAME, "Marquer comme réalisé");
v.add(act);
res.add(act);
 
// Suppression
act = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
TodoListPanel.this.model.deleteTaskAtIndex(TodoListPanel.this.sorter.modelIndex(row));
TodoListPanel.this.model.deleteTaskAtIndex(modelIndex);
table.repaint();
}
};
act.putValue(Action.NAME, "Supprimer");
v.add(act);
res.add(act);
 
final TodoListElement element = TodoListPanel.this.model.getTaskAtRow(TodoListPanel.this.sorter.modelIndex(row));
final TodoListElement element = TodoListPanel.this.model.getTaskAtRow(modelIndex);
SQLRowValues rowTache = element.getRowValues();
 
List<AbstractAction> actions = TacheActionManager.getInstance().getActionsForTaskRow(rowTache);
 
for (AbstractAction abstractAction : actions) {
v.add(abstractAction);
res.add(abstractAction);
}
 
return v;
return res;
}
});
}
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/UserExitPanel.java
19,8 → 19,8
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.utils.BackupPanel;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.UserExit;
 
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
127,12 → 127,7
PostgreSQLFrame pgFrame = null;
 
private void closeGNx() {
Frame[] frames = JFrame.getFrames();
for (int i = 0; i < frames.length; i++) {
if (frames[i] != null) {
frames[i].dispose();
}
}
UserExit.closeAllWindows(null);
ComptaPropsConfiguration.closeOOConnexion();
// ((JFrame) SwingUtilities.getRoot(UserExitingPanel.this)).dispose();
if (Gestion.pgFrameStart != null) {
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/PanelOOSQLComponent.java
New file
0,0 → 1,83
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
/*
* Créé le 11 oct. 2011
*/
package org.openconcerto.erp.panel;
 
import org.openconcerto.erp.preferences.TemplateNXProps;
import org.openconcerto.erp.preferences.TemplatePreferencePanel;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.BaseSQLComponent;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.sqlobject.ElementComboBox;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.utils.cc.ITransformer;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
 
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
 
public class PanelOOSQLComponent extends JPanel {
 
private final JCheckBox checkImpression = new JCheckBox("Imprimer");
private final JCheckBox checkVisu = new JCheckBox("Visualiser");
 
public PanelOOSQLComponent(final BaseSQLComponent comp) {
super(new GridBagLayout());
GridBagConstraints c = new DefaultGridBagConstraints();
c.gridx = GridBagConstraints.RELATIVE;
this.setOpaque(false);
 
if (TemplateNXProps.getInstance().getBooleanValue(TemplatePreferencePanel.MULTIMOD, false)) {
if (comp.getElement().getTable().getFieldsName().contains("ID_MODELE")) {
JLabel labelModele = new JLabel(comp.getLabelFor("ID_MODELE"));
ElementComboBox boxModele = new ElementComboBox();
comp.addView(boxModele, "ID_MODELE");
boxModele.getRequest().setSelectTransf(new ITransformer<SQLSelect, SQLSelect>() {
 
@Override
public SQLSelect transformChecked(SQLSelect input) {
SQLTable table = Configuration.getInstance().getDirectory().getElement("TYPE_MODELE").getTable();
Where w = new Where(table.getField("TABLE"), "=", comp.getElement().getTable().getName());
input.setWhere(w);
System.err.println(input.asString());
return input;
}
});
this.add(labelModele, c);
this.add(boxModele, c);
} else {
System.err.println("Impossible d'ajouter la combo pour le choix des modèles car le champ ID_MODELE n'est pas présent dans la table " + comp.getElement().getTable().getName());
Thread.dumpStack();
}
}
this.add(this.checkImpression, c);
this.add(this.checkVisu, c);
}
 
public boolean isVisualisationSelected() {
return this.checkVisu.isSelected();
}
 
public boolean isImpressionSelected() {
return this.checkImpression.isSelected();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/compta/ExportRelationExpertPanel.java
New file
0,0 → 1,211
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.panel.compta;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.erp.core.finance.accounting.element.JournalSQLElement;
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.ui.DefaultGridBagConstraints;
import org.openconcerto.ui.JDate;
import org.openconcerto.ui.JLabelBold;
import org.openconcerto.utils.GestionDevise;
 
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
 
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
 
import org.apache.commons.dbutils.handlers.ArrayListHandler;
 
public class ExportRelationExpertPanel extends JPanel implements ActionListener {
 
private JDate du, au;
private JButton buttonGen = new JButton("Exporter");
private JButton buttonClose = new JButton("Fermer");
private JFileChooser fileChooser = new JFileChooser();
private JTextField textDestination = new JTextField();
 
public ExportRelationExpertPanel() {
super(new GridBagLayout());
GridBagConstraints c = new DefaultGridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.anchor = GridBagConstraints.CENTER;
this.add(new JLabelBold("Export des écritures comptables"), c);
 
// Fichier de destination
c.gridx = 0;
c.gridy++;
c.gridwidth = 1;
c.weightx = 0;
this.add(new JLabel("Fichier de destination"), c);
 
c.gridx++;
c.weightx = 1;
this.add(textDestination, c);
 
final JButton buttonChoose = new JButton("...");
c.gridx++;
c.weightx = 0;
this.add(buttonChoose, c);
buttonGen.setEnabled(false);
this.textDestination.setEditable(false);
buttonChoose.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int answer = fileChooser.showSaveDialog(ExportRelationExpertPanel.this);
if (answer == JFileChooser.APPROVE_OPTION) {
textDestination.setText(fileChooser.getSelectedFile().getAbsolutePath());
}
 
buttonGen.setEnabled(answer == JFileChooser.APPROVE_OPTION);
}
});
c.gridx = 0;
c.gridwidth = 1;
c.gridy++;
c.anchor = GridBagConstraints.WEST;
this.add(new JLabel("du"), c);
 
c.gridx++;
this.du = new JDate(true);
this.add(this.du, c);
 
c.gridx++;
this.add(new JLabel("au"), c);
 
c.gridx++;
this.au = new JDate(true);
this.add(this.au, c);
 
c.gridy++;
c.gridx = 0;
 
JPanel panelButton = new JPanel();
panelButton.add(this.buttonGen);
panelButton.add(this.buttonClose);
c.gridwidth = GridBagConstraints.REMAINDER;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.CENTER;
c.weightx = 0;
this.add(panelButton, c);
this.buttonGen.addActionListener(this);
this.buttonClose.addActionListener(this);
}
 
private DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
 
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == this.buttonGen) {
File fOut = fileChooser.getSelectedFile();
try {
BufferedOutputStream bufOut = new BufferedOutputStream(new FileOutputStream(fOut.getAbsolutePath() + ".xls"));
 
SQLBase base = ((ComptaPropsConfiguration) Configuration.getInstance()).getSQLBaseSociete();
SQLSelect sel = new SQLSelect(base);
 
SQLTable tableEcriture = base.getTable("ECRITURE");
SQLTable tableMouvement = base.getTable("MOUVEMENT");
SQLTable tableCompte = base.getTable("COMPTE_PCE");
SQLTable tableJrnl = base.getTable("JOURNAL");
 
sel.addSelect(tableEcriture.getField("NOM"));
sel.addJoin("LEFT", "ECRITURE.ID_COMPTE_PCE");
sel.addJoin("LEFT", "ECRITURE.ID_MOUVEMENT");
sel.addJoin("LEFT", "ECRITURE.ID_JOURNAL");
sel.addSelect(tableMouvement.getField("NUMERO"));
sel.addSelect(tableCompte.getField("NUMERO"));
sel.addSelect(tableEcriture.getField("DATE"));
sel.addSelect(tableEcriture.getField("DEBIT"));
sel.addSelect(tableEcriture.getField("CREDIT"));
sel.addSelect(tableJrnl.getField("CODE"));
 
sel.setWhere(new Where(tableEcriture.getField("DATE"), this.du.getDate(), this.au.getDate()).and(new Where(tableEcriture.getField("ID_JOURNAL"), "=", JournalSQLElement.VENTES)));
 
List l = (List) base.getDataSource().execute(sel.asString(), new ArrayListHandler());
System.err.println(sel.asString());
if (l != null) {
for (int i = 0; i < l.size(); i++) {
 
// Ligne à insérer dans le fichier
StringBuffer line = new StringBuffer();
 
Object[] tmp = (Object[]) l.get(i);
 
// Date
Date d = (Date) tmp[3];
line.append(dateFormat.format(d));
line.append('\t');
// Jrnl
line.append(tmp[6].toString().trim());
line.append('\t');
// N° Cpt
String cpt = tmp[2].toString().trim();
line.append(cpt);
line.append('\t');
 
// ?
line.append('\t');
 
// Libellé
line.append(tmp[0].toString().trim());
line.append('\t');
 
// Debit
Long debit = new Long(tmp[4].toString().trim());
line.append(GestionDevise.currencyToString(debit.longValue()));
line.append('\t');
// Credit
Long credit = new Long(tmp[5].toString().trim());
line.append(GestionDevise.currencyToString(credit.longValue()));
line.append('\t');
line.append('E');
line.append('\r');
line.append('\n');
bufOut.write(line.toString().getBytes());
}
}
 
bufOut.close();
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
((JFrame) SwingUtilities.getRoot(this)).dispose();
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/panel/ITreeSelection.java
29,6 → 29,7
import org.openconcerto.utils.checks.EmptyObject;
import org.openconcerto.utils.checks.EmptyObjectHelper;
import org.openconcerto.utils.checks.ValidListener;
import org.openconcerto.utils.checks.ValidState;
 
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
277,9 → 278,10
// TODO Auto-generated method stub
}
 
public boolean isValidated() {
 
return true;
@Override
public ValidState getValidState() {
// return "Aucune valeur sélectionnée dans l'arbre";
return ValidState.getTrueInstance();
}
 
@Override
455,8 → 457,4
 
this.element.getTable().addTableListener(listener);
}
 
public String getValidationText() {
return "Aucune valeur sélectionnée dans l'arbre";
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/model/MouseSheetXmlListeListener.java
23,7 → 23,9
import org.openconcerto.sql.model.SQLRowAccessor;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.view.list.IListe;
import org.openconcerto.sql.view.list.IListeAction.IListeEvent;
import org.openconcerto.sql.view.list.RowAction;
import org.openconcerto.sql.view.list.RowAction.PredicateRowAction;
import org.openconcerto.ui.EmailComposer;
import org.openconcerto.utils.ExceptionHandler;
 
264,13 → 266,13
if (this.showIsVisible) {
l.add(new RowAction(new AbstractAction(this.showString) {
public void actionPerformed(ActionEvent ev) {
createAbstractSheet(liste.getSelectedRow()).showDocument();
createAbstractSheet(IListe.get(ev).getSelectedRow()).showDocument();
}
 
}, false) {
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return createAbstractSheet(liste.getSelectedRow()).isFileODSExist();
public boolean enabledFor(IListeEvent evt) {
return createAbstractSheet(evt.getSelectedRow().asRow()).isFileODSExist();
}
});
 
303,14 → 305,9
for (AbstractAction abstractAction : list) {
// JMenuItem itemItalic = new JMenuItem(abstractAction);
// itemItalic.setFont(itemItalic.getFont().deriveFont(Font.ITALIC));
l.add(new RowAction(abstractAction, false) {
@Override
public boolean enabledFor(List<SQLRowAccessor> selection) {
return selection != null && selection.size() > 0;
l.add(new PredicateRowAction(abstractAction, false).setPredicate(IListeEvent.getNonEmptySelectionPredicate()));
}
});
}
}
 
if (Boolean.getBoolean("org.openconcerto.oo.useODSViewer")) {
 
/trunk/OpenConcerto/src/org/openconcerto/erp/utils/Correct.java
New file
0,0 → 1,37
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.utils;
 
import org.openconcerto.erp.config.ComptaPropsConfiguration;
import org.openconcerto.sql.Configuration;
 
import java.io.IOException;
import java.sql.SQLException;
 
public class Correct extends org.openconcerto.sql.changer.Correct {
 
static public final ComptaPropsConfiguration CONF;
static {
CONF = ComptaPropsConfiguration.create();
Configuration.setInstance(CONF);
}
 
public Correct() {
super(CONF.getSystemRoot());
}
 
public static void main(String[] args) throws IOException, SQLException {
new Correct().exec(args);
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/utils/correct/CorrectMouvement.java
New file
0,0 → 1,116
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
package org.openconcerto.erp.utils.correct;
 
import org.openconcerto.sql.changer.Changer;
import org.openconcerto.sql.model.DBRoot;
import org.openconcerto.sql.model.DBSystemRoot;
import org.openconcerto.sql.model.SQLBase;
import org.openconcerto.sql.model.SQLField;
import org.openconcerto.sql.model.SQLName;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.sql.model.SQLSelect.ArchiveMode;
import org.openconcerto.sql.model.SQLSystem;
import org.openconcerto.sql.model.SQLTable;
import org.openconcerto.sql.model.Where;
import org.openconcerto.sql.request.UpdateBuilder;
 
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
 
/**
* Unarchive ECRITURE to balance MOUVEMENT, then link SAISIE_KM_ELEMENT and a unique matching
* ECRITURE.
*
* @author Sylvain CUAZ
*/
public class CorrectMouvement extends Changer<DBRoot> {
 
public CorrectMouvement(DBSystemRoot b) {
super(b);
}
 
@Override
protected void changeImpl(DBRoot societeRoot) throws SQLException {
final SQLTable ecritureT = societeRoot.getTable("ECRITURE");
 
// some ECRITURE were ARCHIVED creating unbalanced MOUVEMENT
// find MOUVEMENT that would be balanced if we unarchived all of its ECRITURE
{
final SQLField ecritureMvtFF = ecritureT.getField("ID_MOUVEMENT");
final SQLSelect selUnbalanced = new SQLSelect(societeRoot.getBase());
selUnbalanced.addSelect(ecritureMvtFF);
selUnbalanced.addGroupBy(ecritureMvtFF);
selUnbalanced.setHaving(Where.quote(societeRoot.getBase().quote("SUM(%n) != SUM(%n)", ecritureT.getField("DEBIT"), ecritureT.getField("CREDIT"))));
 
final SQLSelect selUnfixable = new SQLSelect(selUnbalanced);
selUnfixable.setArchivedPolicy(ArchiveMode.BOTH);
 
final String selFixableUnbalanced = "( " + selUnbalanced.asString() + "\nEXCEPT\n" + selUnfixable.asString() + " )";
 
final UpdateBuilder updateUnbalanced = new UpdateBuilder(ecritureT);
updateUnbalanced.addTable(selFixableUnbalanced, SQLBase.quoteIdentifier("semiArchivedMvt"));
updateUnbalanced.setWhere(Where.quote("%i = %f", new SQLName("semiArchivedMvt", "ID_MOUVEMENT"), ecritureMvtFF));
updateUnbalanced.set(ecritureT.getArchiveField().getName(), "0");
 
getDS().execute(updateUnbalanced.asString());
}
 
// match SAISIE_KM_ELEMENT with their lost ECRITURE
{
final SQLTable saisieKmElemT = societeRoot.getGraph().findReferentTable(ecritureT, "SAISIE_KM_ELEMENT");
final SQLTable saisieKmT = saisieKmElemT.getForeignTable("ID_SAISIE_KM");
// select ECRITURE which can be identified in a MOUVEMENT by its CREDIT/DEBIT and isn't
// already linked to a SAISIE_KM_ELEMENT
final SQLSelect selIdentifiableNonUsed = new SQLSelect(societeRoot.getBase());
final List<String> uniqueFields = Arrays.asList("ID_MOUVEMENT", "DEBIT", "CREDIT");
selIdentifiableNonUsed.addAllSelect(ecritureT, uniqueFields);
final String quotedID = ecritureT.getKey().getSQLName(ecritureT).quote();
final String uniqueID;
if (getSyntax().getSystem() == SQLSystem.POSTGRESQL)
uniqueID = "(array_agg(" + quotedID + "))[1]";
else
uniqueID = "cast(GROUP_CONCAT(" + quotedID + ") as integer)";
final String uniqueIDAlias = "ID";
selIdentifiableNonUsed.addRawSelect(uniqueID, uniqueIDAlias);
selIdentifiableNonUsed.addBackwardJoin("LEFT", null, saisieKmElemT.getField("ID_ECRITURE"), null);
// unused
selIdentifiableNonUsed.setWhere(Where.isNull(saisieKmElemT.getKey()));
// identifiable
for (final String uniqField : uniqueFields)
selIdentifiableNonUsed.addGroupBy(ecritureT.getField(uniqField));
selIdentifiableNonUsed.setHaving(Where.createRaw("count(*) = 1"));
 
final UpdateBuilder update = new UpdateBuilder(saisieKmElemT);
update.addTable(saisieKmT.getSQLName().quote(), null);
update.addTable("( " + selIdentifiableNonUsed.asString() + " )", "e");
 
final Where joinSaisieKmW = new Where(saisieKmElemT.getField("ID_SAISIE_KM"), "=", saisieKmT.getKey());
Where joinEcritureW = null;
for (final String uniqField : uniqueFields) {
final SQLTable t = uniqField.equals("ID_MOUVEMENT") ? saisieKmT : saisieKmElemT;
joinEcritureW = Where.quote("e." + SQLBase.quoteIdentifier(uniqField) + "= %f", t.getField(uniqField)).and(joinEcritureW);
}
final Where dontOverwrite = new Where(saisieKmElemT.getField("ID_ECRITURE"), Where.NULL_IS_DATA_EQ, ecritureT.getUndefinedIDNumber());
final Where dontUpdateUndef = new Where(saisieKmElemT.getKey(), Where.NULL_IS_DATA_NEQ, saisieKmElemT.getUndefinedIDNumber());
final Where unarchived = new Where(saisieKmElemT.getArchiveField(), "=", 0);
update.setWhere(joinSaisieKmW.and(joinEcritureW).and(dontOverwrite).and(dontUpdateUndef).and(unarchived));
 
update.set("ID_ECRITURE", "e." + SQLBase.quoteIdentifier(uniqueIDAlias));
 
getDS().execute(update.asString());
}
}
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/element/ModeleSQLElement.java
New file
0,0 → 1,72
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
/*
* Créé le 10 oct. 2011
*/
package org.openconcerto.erp.generationDoc.element;
 
import org.openconcerto.erp.core.common.element.ComptaSQLConfElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.UISQLComponent;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.sqlobject.SQLRequestComboBox;
 
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
public class ModeleSQLElement extends ComptaSQLConfElement {
 
public ModeleSQLElement() {
super("MODELE", "un modele ", "modeles");
}
 
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
l.add("NOM");
l.add("ID_TYPE_MODELE");
return l;
}
 
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
l.add("NOM");
l.add("ID_TYPE_MODELE");
return l;
}
 
public SQLComponent createComponent() {
return new UISQLComponent(this) {
 
@Override
protected Set<String> createRequiredNames() {
final Set<String> s = new HashSet<String>();
// s.add("NOM");
// s.add("ID_TYPE_MODELE");
return s;
}
 
public void addViews() {
this.addView("NOM");
this.addView(new SQLRequestComboBox(false), "ID_TYPE_MODELE");
}
};
}
 
public String getDescription(SQLRow fromRow) {
return fromRow.getString("NOM");
}
 
}
/trunk/OpenConcerto/src/org/openconcerto/erp/generationDoc/element/TypeModeleSQLElement.java
New file
0,0 → 1,102
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU General Public License Version 3
* only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
* copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*/
/*
* Créé le 10 oct. 2011
*/
package org.openconcerto.erp.generationDoc.element;
 
import org.openconcerto.sql.Configuration;
import org.openconcerto.sql.element.ConfSQLElement;
import org.openconcerto.sql.element.SQLComponent;
import org.openconcerto.sql.element.UISQLComponent;
import org.openconcerto.sql.model.SQLRow;
import org.openconcerto.sql.model.SQLRowListRSH;
import org.openconcerto.sql.model.SQLSelect;
import org.openconcerto.utils.CollectionMap;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
public class TypeModeleSQLElement extends ConfSQLElement {
 
public TypeModeleSQLElement() {
super("TYPE_MODELE", "un type_modele ", "type_modeles");
}
 
protected List<String> getListFields() {
final List<String> l = new ArrayList<String>();
l.add("NOM");
l.add("TABLE");
return l;
}
 
protected List<String> getComboFields() {
final List<String> l = new ArrayList<String>();
l.add("NOM");
return l;
}
 
@Override
public CollectionMap<String, String> getShowAs() {
CollectionMap<String, String