/* jlayout - A Java code generator for GUI layout Copyright (c) 2007-2010, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 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 COPYRIGHT OWNER OR CONTRIBUTORS 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. */ /** @file jlcheck.c The jlcheck module in the jlayout program. */ /** Inside the jlcheck module. */ #define JLCHECK_C 1 #include "jl.h" #line 50 "jlcheck.ctr" /** Ensure that each object has a class and a name assigned. @param j Jlayout job. @return 1 on success, 0 on error. */ static int all_objects_have_classes_and_names DK_P1(JLJ *,j) { int back = 1; JLO *o; dksto_it_reset(j->o_it); while((o = (JLO *)dksto_it_next(j->o_it)) != NULL) { if(!(o->on)) { back = 0; j->errlineno = o->l_creation; jlmsg_log1(j, DK_LOG_LEVEL_ERROR, 2); } else { if(!jlo_get_classname(o)) { back = 0; j->errlineno = o->l_creation; if(o->on) { jlmsg_log3(j, DK_LOG_LEVEL_ERROR, 3, o->on, 4); } else { jlmsg_log1(j, DK_LOG_LEVEL_ERROR, 5); } } } } return back; } /** Enumerate objects (assign a unique number to each object). @param j Jlayout job. */ static void enumerate_objects DK_P1(JLJ *,j) { JLO *jlo; (j->o_main)->obj_no = 0UL; j->max_obj_no = 0UL; dksto_it_reset(j->o_it); while((jlo = (JLO *)dksto_it_next(j->o_it)) != NULL) { j->max_obj_no += 1UL; jlo->obj_no = j->max_obj_no; } } /** Set bit matrix entries for one objects dependencies. @param j Jlayout job. @param o Object to process. @param bm Bit matrix. */ static void create_entries_for_object DK_P3(JLJ *,j, JLO *,o, dk_bitmatrix_t *,bm) { JCN *jcn; JLO *jlo; if(o->menubar) { dkbf_matrix_set(bm, o->obj_no, (o->menubar)->obj_no, 1); } if((o->c_st) && (o->c_it)) { dksto_it_reset(o->c_it); while((jcn = (JCN *)dksto_it_next(o->c_it)) != NULL) { if((jcn->o) && (jcn->t == JCN_OBJECT)) { jlo = jcn->o; dkbf_matrix_set(bm, o->obj_no, jlo->obj_no, 1); } } } } /** Find levels for objects. @param jlj Jlayout job. @param l Buffer for level numbers. @param sz Number of entries in \a l. @param bm Bit matrix containig object dependencies. @return 1 on success, 0 on error. */ static int find_levels DK_P4(JLJ *,jlj, unsigned long *,l, size_t, sz, dk_bitmatrix_t *,bm) { int back = 1, cc = 0, can_set_level = 0; size_t i, j; unsigned long passno, *ulptr; for(i = 0; i < sz; i++) { if(dkbf_matrix_get(bm, i, i)) { back = 0; /* ERROR: Circular dependencies */ jlmsg_log1(jlj, DK_LOG_LEVEL_ERROR, 14); } } if(back) { /* initialize array */ ulptr = l; for(i = 0; i < sz; i++) { *(ulptr++) = 0UL; } /* multiple passes to assign a level */ cc = 1; passno = 1UL; while(cc) { cc = 0; for(i = 0; i < sz; i++) { if(l[i] == 0UL) { can_set_level = 1; for(j = 0; j < sz; j++) { if(i != j) { if(dkbf_matrix_get(bm, i, j)) { if(l[j] == 0UL) { can_set_level = 0; } } } } if(can_set_level) { l[i] = passno; jlj->max_level = passno; } else { cc = 1; } } } /* count passes, we must not have more passes than objects */ passno++; if(passno >= (unsigned long)sz) { if(cc) { cc = 0; back = 0; /* Emergency stop, internal error */ jlmsg_log1(jlj, DK_LOG_LEVEL_ERROR, 15); } } } } return back; } /** Write object dependencies into bit matrix. @param j Jlayout job. @param bm Bit matrix. */ static void create_bit_matrix_entries DK_P2(JLJ *,j, dk_bitmatrix_t *,bm) { JLO *jlo; create_entries_for_object(j, j->o_main, bm); dksto_it_reset(j->o_it); while((jlo = (JLO *)dksto_it_next(j->o_it)) != NULL) { create_entries_for_object(j, jlo, bm); } } #line 225 "jlcheck.ctr" #line 226 "jlcheck.ctr" #line 227 "jlcheck.ctr" #line 228 "jlcheck.ctr" #line 229 "jlcheck.ctr" #line 230 "jlcheck.ctr" #line 231 "jlcheck.ctr" #line 232 "jlcheck.ctr" #line 233 "jlcheck.ctr" #line 234 "jlcheck.ctr" #line 235 "jlcheck.ctr" #line 236 "jlcheck.ctr" #line 237 "jlcheck.ctr" #line 238 "jlcheck.ctr" #line 239 "jlcheck.ctr" #line 240 "jlcheck.ctr" #line 241 "jlcheck.ctr" #line 242 "jlcheck.ctr" #line 243 "jlcheck.ctr" #line 244 "jlcheck.ctr" #line 245 "jlcheck.ctr" #line 246 "jlcheck.ctr" /** Levelize objects to find order of construction. @param j Jlayout job. @return 1 on success, 0 on error. */ static int levelize_objects DK_P1(JLJ *,j) { int back = 0; unsigned long number_of_objects; size_t sz; unsigned long *levels = NULL; dk_bitmatrix_t *bm = NULL; JLO *jlo; number_of_objects = j->max_obj_no; number_of_objects++; sz = (size_t)number_of_objects; if((unsigned long)sz == number_of_objects) { levels = dk_new(unsigned long,sz); if(levels) { bm = dkbf_matrix_open(sz, sz); if(bm) { create_bit_matrix_entries(j, bm); #line 274 "jlcheck.ctr" dkbf_matrix_expand(bm); #line 276 "jlcheck.ctr" back = find_levels(j, levels, sz, bm); (j->o_main)->obj_lvl = levels[0]; dksto_it_reset(j->o_it); while((jlo = (JLO *)dksto_it_next(j->o_it)) != NULL) { jlo->obj_lvl = levels[jlo->obj_no]; } dkbf_matrix_close(bm); } else { jlmsg_error_memory(j); } dk_delete(levels); } else { jlmsg_error_memory(j); } } else { /* ERROR: Too many objects */ jlmsg_log1(j, DK_LOG_LEVEL_ERROR, 17); } return back; } /** Check gridbag layout for one object. @param j Jlayout job. @param jlo Object to check. @return 1 on success, 0 on error. */ static int do_gbl_check DK_P2(JLJ *,j, JLO *,jlo) { int back = 1; JCN *jcn; JLO *o; long x, y, bx, by, l; size_t sx, sy; long *tx = NULL, *ty = NULL; dk_bitfield_t *bfx1 = NULL, *bfy1 = NULL; /* objects start in line/row */ dk_bitfield_t *bfx2 = NULL, *bfy2 = NULL; /* objects end in line/row */ jlo->grid_layout_r = jlo->grid_layout_c = 0L; jlo->max_x = jlo->max_y = 0L; /* pass 1: find number of rows and columns */ dksto_it_reset(jlo->c_it); while((jcn = (JCN *)dksto_it_next(jlo->c_it)) != NULL) { switch(jcn->t) { case JCN_OBJECT: { if(jcn->o) { o = jcn->o; x = o->pos_x + (o->pos_w - 1L); y = o->pos_y + (o->pos_h - 1L); if(x > jlo->max_x) { jlo->max_x = x; } if(y > jlo->max_y) { jlo->max_y = y; } } } break; default: { /* Error: Dont know how to add glue or separator */ } break; } } bx = jlo->max_x + 2L; by = jlo->max_y + 2L; sx = (size_t)bx; sy = (size_t)by; if(((long)sx == bx) && ((long)sy == by)) { jlo->distance_x = dkbf_open(bx); jlo->distance_y = dkbf_open(by); if((jlo->distance_x) && (jlo->distance_y)) { bfx1 = dkbf_open(bx); bfy1 = dkbf_open(by); bfx2 = dkbf_open(bx); bfy2 = dkbf_open(by); tx = dk_new(long,bx); ty = dk_new(long,by); if((bfx1) && (bfy1) && (bfx2) && (bfy2) && (tx) && (ty)) { dksto_it_reset(jlo->c_it); while((jcn = (JCN *)dksto_it_next(jlo->c_it)) != NULL) { switch(jcn->t) { case JCN_OBJECT: { if(jcn->o) { o = jcn->o; dkbf_set(bfx1, o->pos_x, 1); dkbf_set(bfy1, o->pos_y, 1); x = o->pos_x + o->pos_w; y = o->pos_y + o->pos_h; dkbf_set(bfx2, x, 1); dkbf_set(bfy2, y, 1); } } break; } } for(x = 0L; x < bx; x++) { if(dkbf_get(bfx1, x)) { if(dkbf_get(bfx2, x)) { dkbf_set(jlo->distance_x, x, 1); } } } dkbf_set(jlo->distance_x, 0, 1); dkbf_set(jlo->distance_x, (bx - 1L), 1); for(y = 0L; y < by; y++) { if(dkbf_get(bfy1, y)) { if(dkbf_get(bfy2, y)) { dkbf_set(jlo->distance_y, y, 1); } } } dkbf_set(jlo->distance_y, 0, 1); dkbf_set(jlo->distance_y, (by - 1L), 1); for(x = 0L; x < bx; x++) { tx[x] = x; } for(y = 0L; y < by; y++) { ty[y] = y; } for(x = 0L; x < bx; x++) { if(dkbf_get(jlo->distance_x, x)) { for(l = x; l < bx; l++) { tx[l] += 1L; } } } for(y = 0L; y < by; y++) { if(dkbf_get(jlo->distance_y, y)) { for(l = y; l < by; l++) { ty[l] += 1L; } } } #line 405 "jlcheck.ctr" #line 406 "jlcheck.ctr" #line 407 "jlcheck.ctr" #line 408 "jlcheck.ctr" #line 409 "jlcheck.ctr" #line 410 "jlcheck.ctr" dksto_it_reset(jlo->c_it); while((jcn = (JCN *)dksto_it_next(jlo->c_it)) != NULL) { switch(jcn->t) { case JCN_OBJECT: { if(jcn->o) { o = jcn->o; o->cor_x = tx[o->pos_x]; o->cor_y = ty[o->pos_y]; x = tx[o->pos_x + (o->pos_w - 1L)]; y = ty[o->pos_y + (o->pos_h - 1L)]; if(x > jlo->cor_mx) { jlo->cor_mx = x; } if(y > jlo->cor_my) { jlo->cor_my = y; } o->cor_w = 1L + (x - o->cor_x); o->cor_h = 1L + (y - o->cor_y); } } break; } } } else { back = 0; /* ERROR: Memory */ jlmsg_error_memory(j); } if(bfx1) { dkbf_close(bfx1); bfx1 = NULL; } if(bfy1) { dkbf_close(bfy1); bfy1 = NULL; } if(bfx2) { dkbf_close(bfx2); bfx2 = NULL; } if(bfy2) { dkbf_close(bfy2); bfy2 = NULL; } if(tx) { dk_delete(tx); tx = NULL; } if(ty) { dk_delete(ty); ty = NULL; } } else { back = 0; /* ERROR: Memory */ jlmsg_error_memory(j); } } else { back = 0; /* ERROR: Too many rows or columns */ jlmsg_log1(j, DK_LOG_LEVEL_ERROR, 54); } return back; } /** Check gridbag layout for one object if the object uses gridbag layout. @param j Jlayout job. @param jlo Object to check. @return 1 on success, 0 on error. */ static int gbl_check DK_P2(JLJ *,j, JLO *,jlo) { int back = 1; if(jlo->layout == LAYOUT_GRIDBAG) { back = do_gbl_check(j, jlo); } return back; } /** Check all gridbag layouts. @param j Jlayout job. @return 1 on success, 0 on error. */ static int check_gridbag_layouts DK_P1(JLJ *,j) { int back = 0; JLO *jlo; if(gbl_check(j, j->o_main)) { back = 1; dksto_it_reset(j->o_it); while((jlo = (JLO *)dksto_it_next(j->o_it)) != NULL) { if(!gbl_check(j, jlo)) { back = 0; } } } return back; } /** Check input for consistency. @param j Jlayout job. @return 1 on success, 0 on error. */ int jlcheck DK_P1(JLJ *,j) { int back = 0; char *olderrfilename; olderrfilename = j->errfilename; j->errfilename = j->ifname; if(all_objects_have_classes_and_names(j)) { enumerate_objects(j); if(levelize_objects(j)) { if(check_gridbag_layouts(j)) { back = 1; } } } j->errfilename = olderrfilename; return back; }