blob: 4263bd6f65d6d88d54d6e1e7440304c69eba2103 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* $Id$ */
package org.apache.fop.fo.flow;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.fo.Constants;
/**
* A class to register and resolve markers.
*/
public final class Markers {
// IsAny means either IsFirst or IsLast
private Map<String, Marker> firstQualifyingIsFirst;
private Map<String, Marker> firstQualifyingIsAny;
private Map<String, Marker> lastQualifyingIsFirst;
private Map<String, Marker> lastQualifyingIsLast;
private Map<String, Marker> lastQualifyingIsAny;
private static Log log = LogFactory.getLog(Markers.class);
/**
* Registers a marker with the position traits set.
* Only the required markers are kept.
* For "first-starting-within-page" it adds the markers
* that are starting only if the marker class name is not
* already added.
* For "first-including-carryover" it adds any starting marker
* if the marker class name is not already added.
* For "last-starting-within-page" it adds all marks that
* are starting, replacing earlier markers.
* For "last-ending-within-page" it adds all markers that
* are ending, replacing earlier markers.
*
* @param marks a map of markers to register
* @param starting whether the registration happens at the start (true) or end (false) the the area
* @param isfirst whether it is the first area of the parent LM
* @param islast whether it is the last area of the parent LM
*/
public void register(Map<String, Marker> marks, boolean starting, boolean isfirst, boolean islast) {
// TODO: find way to put the page number in the log tracing
if (marks == null) {
return;
}
if (log.isDebugEnabled()) {
log.debug("--" + marks.keySet() + ": " + (starting ? "starting" : "ending")
+ (isfirst ? ", first" : "") + (islast ? ", last" : ""));
}
if (starting) {
// at the start of the area, register is-first and any areas
if (firstQualifyingIsAny == null) {
firstQualifyingIsAny = new HashMap<String, Marker>();
}
if (isfirst) {
if (firstQualifyingIsFirst == null) {
firstQualifyingIsFirst = new HashMap<String, Marker>();
}
// first on scope: only put in new values, leave current
Set<Map.Entry<String, Marker>> entries = marks.entrySet();
for (Map.Entry<String, Marker> entry : entries) {
String key = entry.getKey();
Marker marker = entry.getValue();
if (!firstQualifyingIsFirst.containsKey(key)) {
firstQualifyingIsFirst.put(key, marker);
if (log.isTraceEnabled()) {
log.trace("Adding marker " + key + " to firstQualifyingIsFirst");
}
}
if (!firstQualifyingIsAny.containsKey(key)) {
firstQualifyingIsAny.put(key, marker);
if (log.isTraceEnabled()) {
log.trace("Adding marker " + key + " to firstQualifyingIsAny");
}
}
}
if (lastQualifyingIsFirst == null) {
lastQualifyingIsFirst = new HashMap<String, Marker>();
}
// last on scope: replace all
lastQualifyingIsFirst.putAll(marks);
if (log.isTraceEnabled()) {
log.trace("Adding all markers to LastStart");
}
} else {
// first on scope: only put in new values, leave current
Set<Map.Entry<String, Marker>> entries = marks.entrySet();
for (Map.Entry<String, Marker> entry : entries) {
String key = entry.getKey();
Marker marker = entry.getValue();
if (!firstQualifyingIsAny.containsKey(key)) {
firstQualifyingIsAny.put(key, marker);
if (log.isTraceEnabled()) {
log.trace("Adding marker " + key + " to firstQualifyingIsAny");
}
}
}
}
} else {
// at the end of the area, register is-last and any areas
if (islast) {
if (lastQualifyingIsLast == null) {
lastQualifyingIsLast = new HashMap<String, Marker>();
}
// last on page: replace all
lastQualifyingIsLast.putAll(marks);
if (log.isTraceEnabled()) {
log.trace("Adding all markers to lastQualifyingIsLast");
}
}
if (lastQualifyingIsAny == null) {
lastQualifyingIsAny = new HashMap<String, Marker>();
}
// last on page: replace all
lastQualifyingIsAny.putAll(marks);
if (log.isTraceEnabled()) {
log.trace("Adding all markers to lastQualifyingIsAny");
}
}
}
/**
* Retrieves the best candidate marker for the given position.
* @return a Marker instance
*/
public Marker resolve(AbstractRetrieveMarker arm) {
Marker mark = null;
int pos = arm.getPosition();
String name = arm.getRetrieveClassName();
String posName = arm.getPositionLabel();
String localName = arm.getLocalName();
switch (pos) {
case Constants.EN_FSWP: // retrieve-marker
case Constants.EN_FIRST_STARTING: // retrieve-table-marker
if (firstQualifyingIsFirst != null) {
mark = firstQualifyingIsFirst.get(name);
}
if (mark == null && firstQualifyingIsAny != null) {
mark = firstQualifyingIsAny.get(name);
posName = "FirstAny after " + posName;
}
break;
case Constants.EN_FIC: // retrieve-marker
case Constants.EN_FIRST_INCLUDING_CARRYOVER: // retrieve-table-marker
if (firstQualifyingIsAny != null) {
mark = firstQualifyingIsAny.get(name);
}
break;
case Constants.EN_LSWP: // retrieve-marker
case Constants.EN_LAST_STARTING: // retrieve-table-marker
if (lastQualifyingIsFirst != null) {
mark = lastQualifyingIsFirst.get(name);
}
if (mark == null && lastQualifyingIsAny != null) {
mark = lastQualifyingIsAny.get(name);
posName = "LastAny after " + posName;
}
break;
case Constants.EN_LEWP: // retrieve-marker
case Constants.EN_LAST_ENDING: // retrieve-table-marker
if (lastQualifyingIsLast != null) {
mark = lastQualifyingIsLast.get(name);
}
if (mark == null && lastQualifyingIsAny != null) {
mark = lastQualifyingIsAny.get(name);
posName = "LastAny after " + posName;
}
break;
default:
throw new RuntimeException("Invalid position attribute in " + localName + ".");
}
if (log.isTraceEnabled()) {
// TODO: find way to put the page number here
log.trace(localName + ": name[" + name + "]; position [" + posName + "]");
}
return mark;
}
/** Dumps the current marker data to the logger. */
public void dump() {
if (log.isTraceEnabled()) {
log.trace("FirstAny: " + this.firstQualifyingIsAny);
log.trace("FirstStart: " + this.firstQualifyingIsFirst);
log.trace("LastAny: " + this.lastQualifyingIsAny);
log.trace("LastEnd: " + this.lastQualifyingIsLast);
log.trace("LastStart: " + this.lastQualifyingIsFirst);
}
}
}