Beispiel #1
0
  /* write mapping support JS to stream */
  protected void writeJSVariables(PrintWriter out, RequestProperties reqState) throws IOException {
    // This var initilizations must not use any functions defined in 'jsmap.js'
    PrivateLabel privLabel = reqState.getPrivateLabel();
    I18N i18n = privLabel.getI18N(JSMap.class);
    Locale locale = reqState.getLocale();
    GeoPoint dftCenter = this.getDefaultCenter(null);
    boolean isFleet = reqState.isFleet();
    Account account = reqState.getCurrentAccount();
    long maxPushpins = this.getMaxPushpins(reqState);
    out.write("// --- Map support Javascript [" + this.getName() + "]\n");
    JavaScriptTools.writeJSVar(out, "MAP_PROVIDER_NAME", this.getName());

    /* properties */
    boolean wrotePropHeader = false;
    RTProperties rtp = this.getProperties();
    for (Iterator<?> i = rtp.keyIterator(); i.hasNext(); ) {
      Object key = i.next();
      if (!this._skipPropKey(key)) {
        if (!wrotePropHeader) {
          // out.write("\n");
          out.write("// Defined properties\n");
          wrotePropHeader = true;
        }
        String val[] = StringTools.parseStringArray(rtp.getProperty(key, "").toString(), '\n');
        String propVar = "PROP_" + key.toString().replace('.', '_').replace('-', '_');
        if (val.length == 1) {
          if (StringTools.isDouble(val[0], true)
              || StringTools.isLong(val[0], true)
              || StringTools.isBoolean(val[0], true)) {
            JavaScriptTools.writeJSVar(out, propVar, val[0], false);
          } else {
            JavaScriptTools.writeJSVar(out, propVar, val[0]);
          }
        } else if (val.length > 1) {
          JavaScriptTools.writeJSVar(out, propVar, StringTools.join(val, "\\n"));
        }
      }
    }

    /* speed units */
    Account.SpeedUnits speedUnits = reqState.getSpeedUnits();
    boolean speedIsKph = speedUnits.equals(Account.SpeedUnits.KPH);
    double altUnitsMult = speedIsKph ? 1.0 : GeoPoint.FEET_PER_METER;
    String altUnitsName =
        speedIsKph
            ? i18n.getString("JSMap.altitude.meters", "Meters")
            : i18n.getString("JSMap.altitude.feet", "Feet");

    /* constants (these do not change during the user session) */
    out.write("// Element IDs\n");
    JavaScriptTools.writeJSVar(out, "MAP_ID", this.getMapID());
    JavaScriptTools.writeJSVar(out, "ID_DETAIL_TABLE", ID_DETAIL_TABLE);
    JavaScriptTools.writeJSVar(out, "ID_DETAIL_CONTROL", ID_DETAIL_CONTROL);
    JavaScriptTools.writeJSVar(out, "ID_LAT_LON_DISPLAY", ID_LAT_LON_DISPLAY);
    JavaScriptTools.writeJSVar(out, "ID_DISTANCE_DISPLAY", ID_DISTANCE_DISPLAY);
    JavaScriptTools.writeJSVar(out, "ID_LATEST_EVENT_DATE", ID_LATEST_EVENT_DATE);
    JavaScriptTools.writeJSVar(out, "ID_LATEST_EVENT_TIME", ID_LATEST_EVENT_TIME);
    JavaScriptTools.writeJSVar(out, "ID_LATEST_EVENT_TMZ", ID_LATEST_EVENT_TMZ);
    JavaScriptTools.writeJSVar(out, "ID_LATEST_BATTERY", ID_LATEST_BATTERY);
    JavaScriptTools.writeJSVar(out, "ID_MESSAGE_TEXT", ID_MESSAGE_TEXT);
    out.write("// Geozone IDs\n");
    JavaScriptTools.writeJSVar(out, "ID_ZONE_LATITUDE_", ID_ZONE_LATITUDE_);
    JavaScriptTools.writeJSVar(out, "ID_ZONE_LONGITUDE_", ID_ZONE_LONGITUDE_);
    JavaScriptTools.writeJSVar(out, "ID_ZONE_RADIUS_M", ID_ZONE_RADIUS_M);
    out.write("// Session constants\n");
    JavaScriptTools.writeJSVar(out, "PUSHPINS_SHOW", rtp.getBoolean(PROP_map_pushpins, true));
    JavaScriptTools.writeJSVar(out, "MAX_PUSH_PINS", maxPushpins);
    JavaScriptTools.writeJSVar(out, "MAX_CREATION_AGE_SEC", rtp.getInt(PROP_map_maxCreationAge, 0));
    JavaScriptTools.writeJSVar(out, "MAP_WIDTH", this.getDimension().getWidth());
    JavaScriptTools.writeJSVar(out, "MAP_HEIGHT", this.getDimension().getHeight());
    JavaScriptTools.writeJSVar(out, "IS_FLEET", isFleet);
    JavaScriptTools.writeJSVar(
        out, "SHOW_SAT_COUNT", rtp.getBoolean(PROP_detail_showSatCount, false));
    JavaScriptTools.writeJSVar(out, "SHOW_SPEED", rtp.getBoolean(PROP_info_showSpeed, true));
    JavaScriptTools.writeJSVar(
        out, "COMBINE_SPEED_HEAD", rtp.getBoolean(PROP_combineSpeedHeading, true));
    JavaScriptTools.writeJSVar(out, "SHOW_ALTITUDE", rtp.getBoolean(PROP_info_showAltitude, false));
    JavaScriptTools.writeJSVar(out, "SHOW_ADDR", reqState.getShowAddress());
    JavaScriptTools.writeJSVar(
        out, "INCL_BLANK_ADDR", rtp.getBoolean(PROP_info_inclBlankAddress, true));
    JavaScriptTools.writeJSVar(
        out, "SHOW_OPT_FIELDS", rtp.getBoolean(PROP_info_showOptionalFields, true));
    JavaScriptTools.writeJSVar(
        out, "INCL_BLANK_OPT_FIELDS", rtp.getBoolean(PROP_info_inclBlankOptFields, true));
    JavaScriptTools.writeJSVar(
        out, "LATLON_FORMAT", Account.getLatLonFormat(account).getIntValue());
    JavaScriptTools.writeJSVar(
        out, "DISTANCE_KM_MULT", reqState.getDistanceUnits().getMultiplier());
    JavaScriptTools.writeJSVar(out, "SPEED_KPH_MULT", speedUnits.getMultiplier());
    JavaScriptTools.writeJSVar(out, "SPEED_UNITS", speedUnits.toString(locale));
    JavaScriptTools.writeJSVar(out, "ALTITUDE_METERS_MULT", altUnitsMult);
    JavaScriptTools.writeJSVar(out, "ALTITUDE_UNITS", altUnitsName);
    JavaScriptTools.writeJSVar(out, "TIME_ZONE", reqState.getTimeZoneString(null)); // long
    JavaScriptTools.writeJSVar(
        out,
        "DEFAULT_CENTER",
        "{ lat:" + dftCenter.getLatitude() + ", lon:" + dftCenter.getLongitude() + " }",
        false);
    JavaScriptTools.writeJSVar(out, "DEFAULT_ZOOM", this.getDefaultZoom(JSMap.DEFAULT_ZOOM, false));
    JavaScriptTools.writeJSVar(out, "PUSHPIN_ZOOM", this.getDefaultZoom(JSMap.PUSHPIN_ZOOM, true));
    JavaScriptTools.writeJSVar(out, "MAP_AUTHORIZATION", this.getAuthorization());
    JavaScriptTools.writeJSVar(
        out, "SCROLL_WHEEL_ZOOM", rtp.getBoolean(PROP_scrollWheelZoom, false));
    JavaScriptTools.writeJSVar(out, "DEFAULT_VIEW", rtp.getString(PROP_map_view, "").toLowerCase());
    JavaScriptTools.writeJSVar(out, "ROUTE_LINE_SHOW", rtp.getBoolean(PROP_map_routeLine, true));
    JavaScriptTools.writeJSVar(
        out, "ROUTE_LINE_COLOR", rtp.getString(PROP_map_routeLine_color, "#FF2222"));
    JavaScriptTools.writeJSVar(
        out, "ROUTE_LINE_ARROWS", rtp.getBoolean(PROP_map_routeLine_arrows, false));
    JavaScriptTools.writeJSVar(
        out,
        "ROUTE_SNAP_TO_ROAD",
        rtp.getBoolean(PROP_map_routeLine_snapToRoad, false)); // Google V2 only
    JavaScriptTools.writeJSVar(out, "REPLAY_INTERVAL", this.getReplayInterval());
    JavaScriptTools.writeJSVar(out, "REPLAY_SINGLE", this.getReplaySinglePushpin());

    /* address title */
    String adrTitles[] = reqState.getAddressTitles();
    String adrTitle = ListTools.itemAt(adrTitles, 0, null);

    /* device title */
    String devTitles[] = reqState.getDeviceTitles();
    String devTitle = ListTools.itemAt(devTitles, 0, null);

    /* labels */
    out.write("// Localized Text/Labels\n");
    JavaScriptTools.writeJSVar(
        out,
        "HEADING",
        "new Array("
            + "\""
            + GeoPoint.CompassHeading.N.toString(locale)
            + "\","
            + "\""
            + GeoPoint.CompassHeading.NE.toString(locale)
            + "\","
            + "\""
            + GeoPoint.CompassHeading.E.toString(locale)
            + "\","
            + "\""
            + GeoPoint.CompassHeading.SE.toString(locale)
            + "\","
            + "\""
            + GeoPoint.CompassHeading.S.toString(locale)
            + "\","
            + "\""
            + GeoPoint.CompassHeading.SW.toString(locale)
            + "\","
            + "\""
            + GeoPoint.CompassHeading.W.toString(locale)
            + "\","
            + "\""
            + GeoPoint.CompassHeading.NW.toString(locale)
            + "\")",
        false);
    JavaScriptTools.writeJSVar(out, "TEXT_INFO_DATE", i18n.getString("JSMap.info.date", "Date"));
    JavaScriptTools.writeJSVar(out, "TEXT_INFO_GPS", i18n.getString("JSMap.info.gps", "GPS"));
    JavaScriptTools.writeJSVar(out, "TEXT_INFO_SATS", i18n.getString("JSMap.info.sats", "#Sats"));
    JavaScriptTools.writeJSVar(out, "TEXT_INFO_SPEED", i18n.getString("JSMap.info.speed", "Speed"));
    JavaScriptTools.writeJSVar(out, "TEXT_INFO_HEADING", GeoPoint.GetHeadingTitle(locale));
    JavaScriptTools.writeJSVar(
        out, "TEXT_INFO_ALTITUDE", i18n.getString("JSMap.info.altitude", "Altitude"));
    JavaScriptTools.writeJSVar(
        out, "TEXT_INFO_STOP_TIME", i18n.getString("JSMap.info.stopTime", "Stop Time"));
    JavaScriptTools.writeJSVar(
        out,
        "TEXT_INFO_ADDR",
        !StringTools.isBlank(adrTitle)
            ? adrTitle
            : i18n.getString("JSMap.info.address", "Address"));
    JavaScriptTools.writeJSVar(
        out,
        "TEXT_DEVICE",
        !StringTools.isBlank(devTitle) ? devTitle : i18n.getString("JSMap.device", "Device"));
    JavaScriptTools.writeJSVar(out, "TEXT_DATE", i18n.getString("JSMap.dateTime", "Date/Time"));
    JavaScriptTools.writeJSVar(out, "TEXT_CODE", i18n.getString("JSMap.code", "Status"));
    JavaScriptTools.writeJSVar(out, "TEXT_LATLON", i18n.getString("JSMap.latLon", "Lat/Lon"));
    JavaScriptTools.writeJSVar(out, "TEXT_SATCOUNT", i18n.getString("JSMap.satCount", "#Sats"));
    JavaScriptTools.writeJSVar(
        out,
        "TEXT_ADDR",
        !StringTools.isBlank(adrTitle) ? adrTitle : i18n.getString("JSMap.address", "Address"));
    JavaScriptTools.writeJSVar(out, "TEXT_SPEED", reqState.getSpeedUnits().toString(locale));
    JavaScriptTools.writeJSVar(out, "TEXT_HEADING", i18n.getString("JSMap.heading", "Heading"));
    JavaScriptTools.writeJSVar(out, "TEXT_DISTANCE", reqState.getDistanceUnits().toString(locale));
    JavaScriptTools.writeJSVar(
        out,
        "TEXT_TIMEOUT",
        i18n.getString("JSMap.sessionTimeout", "Your session has timed-out.\nPlease login ..."));
    JavaScriptTools.writeJSVar(
        out,
        "TEXT_PING_OK",
        i18n.getString(
            "JSMap.pingDevice.ok",
            "A command request has been sent.\nThe {0} should respond shortly ...",
            devTitles));
    JavaScriptTools.writeJSVar(
        out,
        "TEXT_PING_ERROR",
        i18n.getString(
            "JSMap.pingDevice.err",
            "The command request failed.\nThe {0} may not support this feature ...",
            devTitles));
    JavaScriptTools.writeJSVar(
        out,
        "TEXT_MAXPUSHPINS_ALERT",
        i18n.getString(
            "JSMap.maxPushpins.err",
            "The maximum number of allowed pushpins has been exceeded.\n"
                + " [max={0}] Not all pushpins may be displayed on this map.\n"
                + "Adjust the 'From' time to see remaining pushpins",
            String.valueOf(maxPushpins)));
    JavaScriptTools.writeJSVar(
        out,
        "TEXT_MAXPUSHPINS_MSG",
        i18n.getString(
            "JSMap.maxPushpins.msg",
            "Only partial data displayed.  The maximum allowed pushpins has been reached.<BR>"
                + "Adjust the Date/Time range accordingly to view the remaining pushpins."));
    JavaScriptTools.writeJSVar(
        out, "TEXT_UNAVAILABLE", i18n.getString("JSMap.unavailable", "unavailable"));
    JavaScriptTools.writeJSVar(
        out,
        "TEXT_showLocationDetails",
        i18n.getString("JSMap.showLocationDetails", "Show Location Details"));
    JavaScriptTools.writeJSVar(
        out,
        "TEXT_hideLocationDetails",
        i18n.getString("JSMap.hideLocationDetails", "Hide Location Details"));

    /* map "Loading ..." */
    JavaScriptTools.writeJSVar(
        out,
        "TEXT_LOADING_MAP_POINTS",
        (rtp.getBoolean(PROP_MAP_LOADING, false)
            ? i18n.getString("JSMap.loadingMapPoints", "Loading Map Points ...")
            : null));
    JavaScriptTools.writeJSVar(
        out, "MAP_LOADING_IMAGE_URI", rtp.getString(PROP_MAP_LOADING_IMAGE, null));

    /* icons/shadows */
    JSMap.writePushpinArray(out, reqState);

    /* constants (these do not change during the user session) */
    out.write("// Geozone support constants\n");
    JavaScriptTools.writeJSVar(out, "jsvGeozoneMode", false);
    JavaScriptTools.writeJSVar(out, "MAX_ZONE_RADIUS_M", Geozone.MAX_RADIUS_METERS);
    JavaScriptTools.writeJSVar(out, "MIN_ZONE_RADIUS_M", Geozone.MIN_RADIUS_METERS);
    JavaScriptTools.writeJSVar(
        out, "DETAIL_REPORT", this.isFeatureSupported(FEATURE_DETAIL_REPORT));
    JavaScriptTools.writeJSVar(
        out, "DETAIL_INFO_BOX", this.isFeatureSupported(FEATURE_DETAIL_INFO_BOX));
    JavaScriptTools.writeJSVar(out, "TEXT_METERS", GeoPoint.DistanceUnits.METERS.toString(locale));

    /* variables */
    out.write("// TrackMap Vars\n");
    JavaScriptTools.writeJSVar(out, "jsvPoiPins", null);
    JavaScriptTools.writeJSVar(out, "jsvDataSets", null);
    JavaScriptTools.writeJSVar(out, "jsvDetailPoints", null);
    JavaScriptTools.writeJSVar(out, "jsvDetailVisible", false);
    JavaScriptTools.writeJSVar(
        out,
        "jsvDetailAscending",
        privLabel.getBooleanProperty(PrivateLabel.PROP_TrackMap_detailAscending, true));
    JavaScriptTools.writeJSVar(
        out,
        "jsvDetailCenterPushpin",
        privLabel.getBooleanProperty(PrivateLabel.PROP_TrackMap_detailCenterPushpin, false));

    /* last update time */
    TimeZone tmz = reqState.getTimeZone();
    String dateFmt =
        (account != null) ? account.getDateFormat() : BasicPrivateLabel.getDefaultDateFormat();
    String timeFmt =
        (account != null) ? account.getTimeFormat() : BasicPrivateLabel.getDefaultTimeFormat();
    DateTime today = new DateTime(tmz);
    JavaScriptTools.writeJSVar(out, "jsvTodayEpoch", today.getTimeSec());
    JavaScriptTools.writeJSVar(
        out,
        "jsvTodayYMD",
        "{ YYYY:"
            + today.getYear(tmz)
            + ", MM:"
            + today.getMonth1(tmz)
            + ", DD:"
            + today.getDayOfMonth(tmz)
            + " }",
        false);
    JavaScriptTools.writeJSVar(out, "jsvTodayDateFmt", today.format(dateFmt, tmz));
    JavaScriptTools.writeJSVar(out, "jsvTodayTimeFmt", today.format(timeFmt, tmz));
    JavaScriptTools.writeJSVar(out, "jsvTodayTmzFmt", today.format("z", tmz));

    /* last event time */
    out.write("// Last event time\n");
    DateTime lastEventTime = reqState.getLastEventTime();
    if (lastEventTime != null) {
      JavaScriptTools.writeJSVar(out, "jsvLastEventEpoch", lastEventTime.getTimeSec());
      JavaScriptTools.writeJSVar(
          out,
          "jsvLastEventYMD",
          "{ YYYY:"
              + lastEventTime.getYear(tmz)
              + ", MM:"
              + lastEventTime.getMonth1(tmz)
              + ", DD:"
              + lastEventTime.getDayOfMonth(tmz)
              + " }",
          false);
      JavaScriptTools.writeJSVar(out, "jsvLastEventDateFmt", lastEventTime.format(dateFmt, tmz));
      JavaScriptTools.writeJSVar(out, "jsvLastEventTimeFmt", lastEventTime.format(timeFmt, tmz));
      JavaScriptTools.writeJSVar(out, "jsvLastEventTmzFmt", lastEventTime.format("z", tmz));
      JavaScriptTools.writeJSVar(out, "jsvLastBatteryLevel", 0L);
      JavaScriptTools.writeJSVar(out, "jsvLastSignalStrength", 0L);
    } else {
      JavaScriptTools.writeJSVar(out, "jsvLastEventEpoch", 0L);
      JavaScriptTools.writeJSVar(out, "jsvLastEventYMD", null);
      JavaScriptTools.writeJSVar(out, "jsvLastEventDateFmt", null);
      JavaScriptTools.writeJSVar(out, "jsvLastEventTimeFmt", null);
      JavaScriptTools.writeJSVar(out, "jsvLastEventTmzFmt", null);
      JavaScriptTools.writeJSVar(out, "jsvLastBatteryLevel", 0.0);
      JavaScriptTools.writeJSVar(out, "jsvLastSignalStrength", 0.0);
    }

    /* map pointers */
    out.write("// Map vars\n");
    JavaScriptTools.writeJSVar(out, "jsmapElem", null);
    JavaScriptTools.writeJSVar(out, "jsmap", null);
  }
Beispiel #2
0
  private int _writeXML(PrintWriter out, int level, ReportData rd, boolean urlOnly)
      throws ReportException {
    boolean isSoapRequest = rd.isSoapRequest();
    RequestProperties reqState = rd.getRequestProperties();
    PrivateLabel privLabel = rd.getPrivateLabel();
    I18N i18n = privLabel.getI18N(ReportTable.class);
    String PFX1 = XMLTools.PREFIX(isSoapRequest, level * ReportTable.INDENT);
    String PFX2 = XMLTools.PREFIX(isSoapRequest, (level + 1) * ReportTable.INDENT);

    /* begin */
    out.print(PFX1);
    out.print(
        XMLTools.startTAG(
            isSoapRequest,
            "Report", // TAG_Report
            XMLTools.ATTR("name", rd.getReportName())
                + // ATTR_name
                XMLTools.ATTR("type", rd.getReportType()), // ATTR_type
            false,
            true));

    /* constraints */
    ReportConstraints rc = rd.getReportConstraints();
    String dtFmt = DateTime.DEFAULT_DATE_FORMAT + "," + DateTime.DEFAULT_TIME_FORMAT;
    TimeZone tzone = rd.getTimeZone();
    String tzStr = rd.getTimeZoneString();
    long tmBeg = rc.getTimeStart();
    long tmEnd = rc.getTimeEnd();
    DateTime dtStr = new DateTime(tmBeg, tzone);
    DateTime dtEnd = new DateTime(tmEnd, tzone);

    /* Account */
    out.print(PFX2);
    out.print(XMLTools.startTAG(isSoapRequest, "Account", "", false, false)); // TAG_Account
    out.print(XmlFilter(isSoapRequest, rd.getAccountID()));
    out.print(XMLTools.endTAG(isSoapRequest, "Account", true)); // TAG_Account

    /* TimeFrom */
    out.print(PFX2);
    out.print(
        XMLTools.startTAG(
            isSoapRequest,
            "TimeFrom", // TAG_TimeFrom
            XMLTools.ATTR("timestamp", String.valueOf(tmBeg))
                + // ATTR_timestamp
                XMLTools.ATTR("timezone", tzStr), // ATTR_timezone
            false,
            false));
    out.print((tmBeg > 0L) ? XmlFilter(isSoapRequest, dtStr.format(dtFmt)) : "");
    out.print(XMLTools.endTAG(isSoapRequest, "TimeFrom", true)); // TAG_TimeFrom

    /* TimeTo */
    out.print(PFX2);
    out.print(
        XMLTools.startTAG(
            isSoapRequest,
            "TimeTo", // TAG_TimeTo
            XMLTools.ATTR("timestamp", String.valueOf(tmEnd))
                + // ATTR_timestamp
                XMLTools.ATTR("timezone", tzStr), // ATTR_timezone
            false,
            false));
    out.print((tmEnd > 0L) ? XmlFilter(isSoapRequest, dtEnd.format(dtFmt)) : "");
    out.print(XMLTools.endTAG(isSoapRequest, "TimeTo", true)); // TAG_TimeTo

    /* ValidGPSRequired */
    out.print(PFX2);
    out.print(
        XMLTools.startTAG(
            isSoapRequest, "ValidGPSRequired", "", false, false)); // TAG_ValidGPSRequired
    out.print(XmlFilter(isSoapRequest, rc.getValidGPSRequired()));
    out.print(XMLTools.endTAG(isSoapRequest, "ValidGPSRequired", true)); // TAG_ValidGPSRequired

    /* SelectionLimit */
    out.print(PFX2);
    out.print(
        XMLTools.startTAG(
            isSoapRequest,
            "SelectionLimit", // TAG_SelectionLimit
            XMLTools.ATTR("type", rc.getSelectionLimitType()),
            false,
            false));
    out.print(XmlFilter(isSoapRequest, rc.getSelectionLimit()));
    out.print(XMLTools.endTAG(isSoapRequest, "SelectionLimit", true)); // TAG_SelectionLimit

    /* Ascending */
    out.print(PFX2);
    out.print(XMLTools.startTAG(isSoapRequest, "Ascending", "", false, false)); // TAG_Ascending
    out.print(XmlFilter(isSoapRequest, rc.getOrderAscending()));
    out.print(XMLTools.endTAG(isSoapRequest, "Ascending", true)); // TAG_Ascending

    /* ReportLimit */
    out.print(PFX2);
    out.print(XMLTools.startTAG(isSoapRequest, "ReportLimit", "", false, false)); // TAG_ReportLimit
    out.print(XmlFilter(isSoapRequest, rc.getReportLimit()));
    out.print(XMLTools.endTAG(isSoapRequest, "ReportLimit", true)); // TAG_ReportLimit

    /* Where */
    if (rc.hasWhere()) {
      out.print(PFX2);
      out.print(XMLTools.startTAG(isSoapRequest, "Where", "", false, false)); // TAG_Where
      out.print(XmlFilter(isSoapRequest, rc.getWhere()));
      out.print(XMLTools.endTAG(isSoapRequest, "Where", true)); // TAG_Where
    }

    /* RuleSelector */
    if (rc.hasRuleSelector()) {
      out.print(PFX2);
      out.print(
          XMLTools.startTAG(isSoapRequest, "RuleSelector", "", false, false)); // TAG_RuleSelector
      out.print(XmlFilter(isSoapRequest, rc.getRuleSelector()));
      out.print(XMLTools.endTAG(isSoapRequest, "RuleSelector", true)); // TAG_RuleSelector
    }

    /* Title */
    out.print(PFX2);
    out.print(XMLTools.startTAG(isSoapRequest, "Title", "", false, false)); // TAG_Title
    out.print(XmlFilter(isSoapRequest, rd.getReportTitle()));
    out.print(XMLTools.endTAG(isSoapRequest, "Title", true)); // TAG_Title

    /* Subtitle */
    out.print(PFX2);
    out.print(XMLTools.startTAG(isSoapRequest, "Subtitle", "", false, false)); // TAG_Subtitle
    out.print(XmlFilter(isSoapRequest, rd.getReportSubtitle()));
    out.print(XMLTools.endTAG(isSoapRequest, "Subtitle", true)); // TAG_Subtitle

    /* URL */
    if (urlOnly) {
      // Web-URL only
      HttpServletRequest request = reqState.getHttpServletRequest();
      ReportDeviceList devList = rd.getReportDeviceList();
      String deviceID = devList.isDeviceGroup() ? null : devList.getFirstDeviceID();
      String groupID = devList.isDeviceGroup() ? devList.getDeviceGroupID() : null;
      String baseURL =
          privLabel.hasDefaultBaseURL()
              ? privLabel.getDefaultBaseURL()
              : ((request != null) ? request.getRequestURL().toString() : "");
      URIArg rptURL =
          ReportURL.createReportURL(
              baseURL,
              false,
              rd.getAccountID(),
              rd.getUserID(),
              "",
              deviceID,
              groupID,
              rc.getTimeStart(),
              rc.getTimeEnd(),
              rd.getTimeZoneString(),
              rd.getReportName(),
              rc.getReportLimit(),
              rc.getSelectionLimitType().toString(),
              ReportPresentation.FORMAT_HTML);
      out.print(PFX2);
      out.print(XMLTools.startTAG(isSoapRequest, "URL", "", false, false)); // TAG_URL
      out.print(XmlFilter(isSoapRequest, rptURL.toString()));
      out.print(XMLTools.endTAG(isSoapRequest, "URL", true)); // TAG_URL
    } else {
      // Report header/body
      this.rptHeader.writeXML(out, level + 1, rd);
      this.rptBody.writeXML(out, level + 1, rd);
    }

    /* Partial */
    out.print(PFX2);
    out.print(XMLTools.startTAG(isSoapRequest, "Partial", "", false, false)); // TAG_Partial
    out.print(XmlFilter(isSoapRequest, this.rptBody.isPartial()));
    out.print(XMLTools.endTAG(isSoapRequest, "Partial", true)); // TAG_Partial

    /* end of report */
    out.print(PFX1);
    out.print(XMLTools.endTAG(isSoapRequest, "Report", true)); // TAG_Report
    return this.rptBody.getRecordCount();
  }