mirror of https://github.com/apache/poi.git
#65694 - HSLF - handle date/time fields and formats
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1895248 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
84957d7bc4
commit
d3ff953cf7
|
@ -70,7 +70,7 @@ implements Slide<XSLFShape,XSLFTextParagraph> {
|
||||||
* Construct a SpreadsheetML slide from a package part
|
* Construct a SpreadsheetML slide from a package part
|
||||||
*
|
*
|
||||||
* @param part the package part holding the slide data,
|
* @param part the package part holding the slide data,
|
||||||
* the content type must be <code>application/vnd.openxmlformats-officedocument.slide+xml</code>
|
* the content type must be {@code application/vnd.openxmlformats-officedocument.slide+xml}
|
||||||
*
|
*
|
||||||
* @since POI 3.14-Beta1
|
* @since POI 3.14-Beta1
|
||||||
*/
|
*/
|
||||||
|
@ -377,12 +377,6 @@ implements Slide<XSLFShape,XSLFTextParagraph> {
|
||||||
draw.draw(graphics);
|
draw.draw(graphics);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getDisplayPlaceholder(Placeholder placeholder) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setHidden(boolean hidden) {
|
public void setHidden(boolean hidden) {
|
||||||
CTSlide sld = getXmlObject();
|
CTSlide sld = getXmlObject();
|
||||||
|
|
|
@ -206,6 +206,18 @@ public final class HeadersFooters {
|
||||||
return isVisible(HeadersFootersAtom.fHasUserDate, Placeholder.DATETIME);
|
return isVisible(HeadersFootersAtom.fHasUserDate, Placeholder.DATETIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CString getHeaderAtom() {
|
||||||
|
return _container.getHeaderAtom();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CString getFooterAtom() {
|
||||||
|
return _container.getFooterAtom();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CString getUserDateAtom() {
|
||||||
|
return _container.getUserDateAtom();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* whether the date is displayed in the footer.
|
* whether the date is displayed in the footer.
|
||||||
*/
|
*/
|
||||||
|
@ -213,6 +225,20 @@ public final class HeadersFooters {
|
||||||
setFlag(HeadersFootersAtom.fHasUserDate, flag);
|
setFlag(HeadersFootersAtom.fHasUserDate, flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* whether today's date is used.
|
||||||
|
*/
|
||||||
|
public boolean isTodayDateVisible(){
|
||||||
|
return isVisible(HeadersFootersAtom.fHasTodayDate, Placeholder.DATETIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* whether the todays date is displayed in the footer.
|
||||||
|
*/
|
||||||
|
public void setTodayDateVisible(boolean flag){
|
||||||
|
setFlag(HeadersFootersAtom.fHasTodayDate, flag);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* whether the slide number is displayed in the footer.
|
* whether the slide number is displayed in the footer.
|
||||||
*/
|
*/
|
||||||
|
@ -282,4 +308,8 @@ public final class HeadersFooters {
|
||||||
public boolean isPpt2007() {
|
public boolean isPpt2007() {
|
||||||
return _ppt2007;
|
return _ppt2007;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HeadersFootersContainer getContainer() {
|
||||||
|
return _container;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
package org.apache.poi.hslf.record;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.apache.poi.util.GenericRecordUtil;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
public class DateTimeMCAtom extends RecordAtom {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record header.
|
||||||
|
*/
|
||||||
|
private final byte[] _header;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A TextPosition that specifies the position of the metacharacter in the corresponding text.
|
||||||
|
*/
|
||||||
|
private int position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An unsigned byte that specifies the Format ID used to stylize datetime. The identifier specified by
|
||||||
|
* the Format ID is converted based on the LCID [MS-LCID] into a value or string as specified in the
|
||||||
|
* following tables. The LCID is specified in TextSIException.lid. If no valid LCID is found in
|
||||||
|
* TextSIException.lid, TextSIException.altLid (if it exists) is used.
|
||||||
|
* The value MUST be greater than or equal to 0x0 and MUST be less than or equal to 0xC.
|
||||||
|
*/
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
private final byte[] unused = new byte[3];
|
||||||
|
|
||||||
|
protected DateTimeMCAtom() {
|
||||||
|
_header = new byte[8];
|
||||||
|
position = 0;
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
LittleEndian.putShort(_header, 2, (short)getRecordType());
|
||||||
|
LittleEndian.putInt(_header, 4, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the datetime atom record from its source data.
|
||||||
|
*
|
||||||
|
* @param source the source data as a byte array.
|
||||||
|
* @param start the start offset into the byte array.
|
||||||
|
* @param len the length of the slice in the byte array.
|
||||||
|
*/
|
||||||
|
protected DateTimeMCAtom(byte[] source, int start, int len) {
|
||||||
|
// Get the header.
|
||||||
|
_header = Arrays.copyOfRange(source, start, start+8);
|
||||||
|
|
||||||
|
position = LittleEndian.getInt(source, start+8);
|
||||||
|
index = LittleEndian.getUByte(source, start+12);
|
||||||
|
System.arraycopy(source, start+13, unused, 0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the contents of the record back, so it can be written
|
||||||
|
* to disk
|
||||||
|
*
|
||||||
|
* @param out the output stream to write to.
|
||||||
|
* @throws IOException if an error occurs.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void writeOut(OutputStream out) throws IOException {
|
||||||
|
out.write(_header);
|
||||||
|
LittleEndian.putInt(position, out);
|
||||||
|
out.write(index);
|
||||||
|
out.write(unused);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPosition(int position) {
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndex(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the record type.
|
||||||
|
* @return the record type.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public long getRecordType() {
|
||||||
|
return RecordTypes.DateTimeMCAtom.typeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Supplier<?>> getGenericProperties() {
|
||||||
|
return GenericRecordUtil.getGenericProperties(
|
||||||
|
"position", this::getPosition,
|
||||||
|
"index", this::getIndex
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -18,7 +18,6 @@
|
||||||
package org.apache.poi.hslf.record;
|
package org.apache.poi.hslf.record;
|
||||||
|
|
||||||
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
|
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
|
||||||
import static org.apache.poi.util.GenericRecordUtil.safeEnum;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -37,30 +36,6 @@ import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
public final class HeadersFootersAtom extends RecordAtom {
|
public final class HeadersFootersAtom extends RecordAtom {
|
||||||
|
|
||||||
/** FormatIndex enum without LCID mapping */
|
|
||||||
public enum FormatIndex {
|
|
||||||
SHORT_DATE,
|
|
||||||
LONG_DATE,
|
|
||||||
LONG_DATE_WITHOUT_WEEKDAY,
|
|
||||||
ALTERNATE_SHORT_DATE,
|
|
||||||
ISO_STANDARD_DATE,
|
|
||||||
SHORT_DATE_WITH_ABBREVIATED_MONTH,
|
|
||||||
SHORT_DATE_WITH_SLASHES,
|
|
||||||
ALTERNATE_SHORT_DATE_WITH_ABBREVIATED_MONTH,
|
|
||||||
ENGLISH_DATE,
|
|
||||||
MONTH_AND_YEAR,
|
|
||||||
ABBREVIATED_MONTH_AND_YEAR,
|
|
||||||
DATE_AND_HOUR12_TIME,
|
|
||||||
DATE_AND_HOUR12_TIME_WITH_SECONDS,
|
|
||||||
HOUR12_TIME,
|
|
||||||
HOUR12_TIME_WITH_SECONDS,
|
|
||||||
HOUR24_TIME,
|
|
||||||
HOUR24_TIME_WITH_SECONDS,
|
|
||||||
CHINESE1,
|
|
||||||
CHINESE2,
|
|
||||||
CHINESE3
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A bit that specifies whether the date is displayed in the footer.
|
* A bit that specifies whether the date is displayed in the footer.
|
||||||
* @see #getMask()
|
* @see #getMask()
|
||||||
|
@ -136,7 +111,7 @@ public final class HeadersFootersAtom extends RecordAtom {
|
||||||
/**
|
/**
|
||||||
* Build an instance of {@code HeadersFootersAtom} from on-disk data
|
* Build an instance of {@code HeadersFootersAtom} from on-disk data
|
||||||
*/
|
*/
|
||||||
protected HeadersFootersAtom(byte[] source, int start, int len) {
|
HeadersFootersAtom(byte[] source, int start, int len) {
|
||||||
// Get the header
|
// Get the header
|
||||||
_header = Arrays.copyOfRange(source, start, start+8);
|
_header = Arrays.copyOfRange(source, start, start+8);
|
||||||
|
|
||||||
|
@ -182,6 +157,7 @@ public final class HeadersFootersAtom extends RecordAtom {
|
||||||
return LittleEndian.getShort(_recdata, 0);
|
return LittleEndian.getShort(_recdata, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A signed integer that specifies the format ID to be used to style the datetime.
|
* A signed integer that specifies the format ID to be used to style the datetime.
|
||||||
*
|
*
|
||||||
|
@ -258,7 +234,7 @@ public final class HeadersFootersAtom extends RecordAtom {
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Supplier<?>> getGenericProperties() {
|
public Map<String, Supplier<?>> getGenericProperties() {
|
||||||
return GenericRecordUtil.getGenericProperties(
|
return GenericRecordUtil.getGenericProperties(
|
||||||
"formatIndex", safeEnum(FormatIndex.values(), this::getFormatId),
|
"formatIndex", this::getFormatId,
|
||||||
"flags", getBitsAsString(this::getMask, PLACEHOLDER_MASKS, PLACEHOLDER_NAMES)
|
"flags", getBitsAsString(this::getMask, PLACEHOLDER_MASKS, PLACEHOLDER_NAMES)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ public final class OEPlaceholderAtom extends RecordAtom{
|
||||||
*/
|
*/
|
||||||
public static final int PLACEHOLDER_QUARTSIZE = 2;
|
public static final int PLACEHOLDER_QUARTSIZE = 2;
|
||||||
|
|
||||||
private byte[] _header;
|
private final byte[] _header;
|
||||||
|
|
||||||
private int placementId;
|
private int placementId;
|
||||||
private int placeholderId;
|
private int placeholderId;
|
||||||
|
@ -77,7 +77,7 @@ public final class OEPlaceholderAtom extends RecordAtom{
|
||||||
/**
|
/**
|
||||||
* Build an instance of {@code OEPlaceholderAtom} from on-disk data
|
* Build an instance of {@code OEPlaceholderAtom} from on-disk data
|
||||||
*/
|
*/
|
||||||
protected OEPlaceholderAtom(byte[] source, int start, int len) {
|
OEPlaceholderAtom(byte[] source, int start, int len) {
|
||||||
_header = Arrays.copyOfRange(source, start, start+8);
|
_header = Arrays.copyOfRange(source, start, start+8);
|
||||||
int offset = start+8;
|
int offset = start+8;
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ public final class OEPlaceholderAtom extends RecordAtom{
|
||||||
* Sets the placeholder Id.<p>
|
* Sets the placeholder Id.<p>
|
||||||
*
|
*
|
||||||
* placeholder Id specifies the type of the placeholder shape.
|
* placeholder Id specifies the type of the placeholder shape.
|
||||||
* The value MUST be one of the static constants defined in this class
|
* The value MUST be one of the static constants defined in {@link Placeholder}
|
||||||
*
|
*
|
||||||
* @param id the placeholder Id.
|
* @param id the placeholder Id.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -134,7 +134,7 @@ public enum RecordTypes {
|
||||||
InteractiveInfoAtom(4083,InteractiveInfoAtom::new),
|
InteractiveInfoAtom(4083,InteractiveInfoAtom::new),
|
||||||
UserEditAtom(4085,UserEditAtom::new),
|
UserEditAtom(4085,UserEditAtom::new),
|
||||||
CurrentUserAtom(4086,null),
|
CurrentUserAtom(4086,null),
|
||||||
DateTimeMCAtom(4087,null),
|
DateTimeMCAtom(4087,DateTimeMCAtom::new),
|
||||||
GenericDateMCAtom(4088,null),
|
GenericDateMCAtom(4088,null),
|
||||||
FooterMCAtom(4090,null),
|
FooterMCAtom(4090,null),
|
||||||
ExControlAtom(4091,ExControlAtom::new),
|
ExControlAtom(4091,ExControlAtom::new),
|
||||||
|
|
|
@ -36,6 +36,7 @@ public class HSLFPlaceholderDetails implements PlaceholderDetails {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isVisible() {
|
public boolean isVisible() {
|
||||||
final Placeholder ph = getPlaceholder();
|
final Placeholder ph = getPlaceholder();
|
||||||
if (ph == null) {
|
if (ph == null) {
|
||||||
|
@ -46,13 +47,12 @@ public class HSLFPlaceholderDetails implements PlaceholderDetails {
|
||||||
|
|
||||||
switch (ph) {
|
switch (ph) {
|
||||||
case HEADER:
|
case HEADER:
|
||||||
|
case TITLE:
|
||||||
return headersFooters.isHeaderVisible();
|
return headersFooters.isHeaderVisible();
|
||||||
case FOOTER:
|
case FOOTER:
|
||||||
return headersFooters.isFooterVisible();
|
return headersFooters.isFooterVisible();
|
||||||
case DATETIME:
|
case DATETIME:
|
||||||
return headersFooters.isDateTimeVisible();
|
return headersFooters.isDateTimeVisible();
|
||||||
case TITLE:
|
|
||||||
return headersFooters.isHeaderVisible();
|
|
||||||
case SLIDE_NUMBER:
|
case SLIDE_NUMBER:
|
||||||
return headersFooters.isSlideNumberVisible();
|
return headersFooters.isSlideNumberVisible();
|
||||||
default:
|
default:
|
||||||
|
@ -60,6 +60,7 @@ public class HSLFPlaceholderDetails implements PlaceholderDetails {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setVisible(final boolean isVisible) {
|
public void setVisible(final boolean isVisible) {
|
||||||
final Placeholder ph = getPlaceholder();
|
final Placeholder ph = getPlaceholder();
|
||||||
if (ph == null) {
|
if (ph == null) {
|
||||||
|
|
|
@ -17,15 +17,29 @@
|
||||||
|
|
||||||
package org.apache.poi.hslf.usermodel;
|
package org.apache.poi.hslf.usermodel;
|
||||||
|
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.apache.poi.ddf.EscherPropertyTypes;
|
import org.apache.poi.ddf.EscherPropertyTypes;
|
||||||
import org.apache.poi.ddf.EscherSpRecord;
|
import org.apache.poi.ddf.EscherSpRecord;
|
||||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||||
|
import org.apache.poi.hslf.model.HeadersFooters;
|
||||||
|
import org.apache.poi.hslf.record.CString;
|
||||||
|
import org.apache.poi.hslf.record.DateTimeMCAtom;
|
||||||
|
import org.apache.poi.hslf.record.EscherTextboxWrapper;
|
||||||
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
|
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
|
||||||
|
import org.apache.poi.hslf.record.HeadersFootersAtom;
|
||||||
import org.apache.poi.hslf.record.OEPlaceholderAtom;
|
import org.apache.poi.hslf.record.OEPlaceholderAtom;
|
||||||
import org.apache.poi.hslf.record.Record;
|
import org.apache.poi.hslf.record.RecordTypes;
|
||||||
import org.apache.poi.hslf.record.RoundTripHFPlaceholder12;
|
import org.apache.poi.hslf.record.RoundTripHFPlaceholder12;
|
||||||
|
import org.apache.poi.hslf.record.TextSpecInfoAtom;
|
||||||
|
import org.apache.poi.hslf.record.TextSpecInfoRun;
|
||||||
|
import org.apache.poi.hslf.util.LocaleDateFormat;
|
||||||
import org.apache.poi.sl.usermodel.MasterSheet;
|
import org.apache.poi.sl.usermodel.MasterSheet;
|
||||||
import org.apache.poi.sl.usermodel.Placeholder;
|
import org.apache.poi.sl.usermodel.Placeholder;
|
||||||
|
import org.apache.poi.util.LocaleID;
|
||||||
|
import org.apache.poi.util.LocaleUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extended placeholder details for HSLF shapes
|
* Extended placeholder details for HSLF shapes
|
||||||
|
@ -41,6 +55,7 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails {
|
||||||
final HSLFSimpleShape shape;
|
final HSLFSimpleShape shape;
|
||||||
private OEPlaceholderAtom oePlaceholderAtom;
|
private OEPlaceholderAtom oePlaceholderAtom;
|
||||||
private RoundTripHFPlaceholder12 roundTripHFPlaceholder12;
|
private RoundTripHFPlaceholder12 roundTripHFPlaceholder12;
|
||||||
|
private DateTimeMCAtom localDateTime;
|
||||||
|
|
||||||
|
|
||||||
HSLFShapePlaceholderDetails(final HSLFSimpleShape shape) {
|
HSLFShapePlaceholderDetails(final HSLFSimpleShape shape) {
|
||||||
|
@ -61,6 +76,7 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Placeholder getPlaceholder() {
|
public Placeholder getPlaceholder() {
|
||||||
updatePlaceholderAtom(false);
|
updatePlaceholderAtom(false);
|
||||||
final int phId;
|
final int phId;
|
||||||
|
@ -68,6 +84,8 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails {
|
||||||
phId = oePlaceholderAtom.getPlaceholderId();
|
phId = oePlaceholderAtom.getPlaceholderId();
|
||||||
} else if (roundTripHFPlaceholder12 != null) {
|
} else if (roundTripHFPlaceholder12 != null) {
|
||||||
phId = roundTripHFPlaceholder12.getPlaceholderId();
|
phId = roundTripHFPlaceholder12.getPlaceholderId();
|
||||||
|
} else if (localDateTime != null) {
|
||||||
|
return Placeholder.DATETIME;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -85,6 +103,7 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setPlaceholder(final Placeholder placeholder) {
|
public void setPlaceholder(final Placeholder placeholder) {
|
||||||
final EscherSpRecord spRecord = shape.getEscherChild(EscherSpRecord.RECORD_ID);
|
final EscherSpRecord spRecord = shape.getEscherChild(EscherSpRecord.RECORD_ID);
|
||||||
int flags = spRecord.getFlags();
|
int flags = spRecord.getFlags();
|
||||||
|
@ -111,6 +130,7 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails {
|
||||||
roundTripHFPlaceholder12.setPlaceholderId(phId);
|
roundTripHFPlaceholder12.setPlaceholderId(phId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public PlaceholderSize getSize() {
|
public PlaceholderSize getSize() {
|
||||||
final Placeholder ph = getPlaceholder();
|
final Placeholder ph = getPlaceholder();
|
||||||
if (ph == null) {
|
if (ph == null) {
|
||||||
|
@ -132,6 +152,7 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setSize(final PlaceholderSize size) {
|
public void setSize(final PlaceholderSize size) {
|
||||||
final Placeholder ph = getPlaceholder();
|
final Placeholder ph = getPlaceholder();
|
||||||
if (ph == null || size == null) {
|
if (ph == null || size == null) {
|
||||||
|
@ -202,6 +223,14 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePlaceholderAtom(final boolean create) {
|
private void updatePlaceholderAtom(final boolean create) {
|
||||||
|
localDateTime = null;
|
||||||
|
if (shape instanceof HSLFTextBox) {
|
||||||
|
EscherTextboxWrapper txtBox = ((HSLFTextBox)shape).getEscherTextboxWrapper();
|
||||||
|
if (txtBox != null) {
|
||||||
|
localDateTime = (DateTimeMCAtom)txtBox.findFirstOfType(RecordTypes.DateTimeMCAtom.typeID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final HSLFEscherClientDataRecord clientData = shape.getClientData(create);
|
final HSLFEscherClientDataRecord clientData = shape.getClientData(create);
|
||||||
if (clientData == null) {
|
if (clientData == null) {
|
||||||
oePlaceholderAtom = null;
|
oePlaceholderAtom = null;
|
||||||
|
@ -237,4 +266,38 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails {
|
||||||
clientData.addChild(roundTripHFPlaceholder12);
|
clientData.addChild(roundTripHFPlaceholder12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserDate() {
|
||||||
|
HeadersFooters hf = shape.getSheet().getHeadersFooters();
|
||||||
|
CString uda = hf.getUserDateAtom();
|
||||||
|
return hf.isUserDateVisible() && uda != null ? uda.getText() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DateTimeFormatter getDateFormat() {
|
||||||
|
int formatId;
|
||||||
|
if (localDateTime != null) {
|
||||||
|
formatId = localDateTime.getIndex();
|
||||||
|
} else {
|
||||||
|
HeadersFootersAtom hfAtom = shape.getSheet().getHeadersFooters().getContainer().getHeadersFootersAtom();
|
||||||
|
formatId = hfAtom.getFormatId();
|
||||||
|
}
|
||||||
|
|
||||||
|
LocaleID def = LocaleID.lookupByLanguageTag(LocaleUtil.getUserLocale().toLanguageTag());
|
||||||
|
|
||||||
|
// def = LocaleID.EN_US;
|
||||||
|
|
||||||
|
LocaleID lcid =
|
||||||
|
Stream.of(((HSLFTextShape)shape).getTextParagraphs().get(0).getRecords())
|
||||||
|
.filter(r -> r instanceof TextSpecInfoAtom)
|
||||||
|
.findFirst()
|
||||||
|
.map(r -> ((TextSpecInfoAtom)r).getTextSpecInfoRuns()[0])
|
||||||
|
.map(TextSpecInfoRun::getLangId)
|
||||||
|
.flatMap(lid -> Optional.ofNullable(LocaleID.lookupByLcid(lid)))
|
||||||
|
.orElse(def != null ? def : LocaleID.EN_US)
|
||||||
|
;
|
||||||
|
|
||||||
|
return LocaleDateFormat.map(lcid, formatId, LocaleDateFormat.MapFormatId.PPT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ import org.apache.poi.sl.draw.Drawable;
|
||||||
import org.apache.poi.sl.usermodel.Notes;
|
import org.apache.poi.sl.usermodel.Notes;
|
||||||
import org.apache.poi.sl.usermodel.Placeholder;
|
import org.apache.poi.sl.usermodel.Placeholder;
|
||||||
import org.apache.poi.sl.usermodel.ShapeType;
|
import org.apache.poi.sl.usermodel.ShapeType;
|
||||||
|
import org.apache.poi.sl.usermodel.SimpleShape;
|
||||||
import org.apache.poi.sl.usermodel.Slide;
|
import org.apache.poi.sl.usermodel.Slide;
|
||||||
import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
|
import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
|
||||||
|
|
||||||
|
@ -259,7 +260,7 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFTe
|
||||||
* @return set of records inside {@code SlideListWithtext} container
|
* @return set of records inside {@code SlideListWithtext} container
|
||||||
* which hold text data for this slide (typically for placeholders).
|
* which hold text data for this slide (typically for placeholders).
|
||||||
*/
|
*/
|
||||||
protected SlideAtomsSet getSlideAtomsSet() { return _atomSet; }
|
public SlideAtomsSet getSlideAtomsSet() { return _atomSet; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns master sheet associated with this slide.
|
* Returns master sheet associated with this slide.
|
||||||
|
@ -495,13 +496,36 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFTe
|
||||||
(slt == SlideLayoutType.TITLE_SLIDE || slt == SlideLayoutType.TITLE_ONLY || slt == SlideLayoutType.MASTER_TITLE);
|
(slt == SlideLayoutType.TITLE_SLIDE || slt == SlideLayoutType.TITLE_ONLY || slt == SlideLayoutType.MASTER_TITLE);
|
||||||
switch (placeholder) {
|
switch (placeholder) {
|
||||||
case DATETIME:
|
case DATETIME:
|
||||||
return hf.isDateTimeVisible() && !isTitle;
|
return (hf.isDateTimeVisible() && (hf.isTodayDateVisible() || (hf.isUserDateVisible() && hf.getUserDateAtom() != null))) && !isTitle;
|
||||||
case SLIDE_NUMBER:
|
case SLIDE_NUMBER:
|
||||||
return hf.isSlideNumberVisible() && !isTitle;
|
return hf.isSlideNumberVisible() && !isTitle;
|
||||||
case HEADER:
|
case HEADER:
|
||||||
return hf.isHeaderVisible() && !isTitle;
|
return hf.isHeaderVisible() && hf.getHeaderAtom() != null && !isTitle;
|
||||||
case FOOTER:
|
case FOOTER:
|
||||||
return hf.isFooterVisible() && !isTitle;
|
return hf.isFooterVisible() && hf.getFooterAtom() != null && !isTitle;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getDisplayPlaceholder(final SimpleShape<?,?> placeholderRef) {
|
||||||
|
Placeholder placeholder = placeholderRef.getPlaceholder();
|
||||||
|
if (placeholder == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final HeadersFooters hf = getHeadersFooters();
|
||||||
|
final SlideLayoutType slt = getSlideRecord().getSlideAtom().getSSlideLayoutAtom().getGeometryType();
|
||||||
|
final boolean isTitle =
|
||||||
|
(slt == SlideLayoutType.TITLE_SLIDE || slt == SlideLayoutType.TITLE_ONLY || slt == SlideLayoutType.MASTER_TITLE);
|
||||||
|
switch (placeholder) {
|
||||||
|
case HEADER:
|
||||||
|
return hf.isHeaderVisible() && hf.getHeaderAtom() != null && !isTitle;
|
||||||
|
case FOOTER:
|
||||||
|
return hf.isFooterVisible() && hf.getFooterAtom() != null && !isTitle;
|
||||||
|
case DATETIME:
|
||||||
|
case SLIDE_NUMBER:
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,364 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.
|
||||||
|
==================================================================== */
|
||||||
|
|
||||||
|
package org.apache.poi.hslf.util;
|
||||||
|
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeFormatterBuilder;
|
||||||
|
import java.time.format.FormatStyle;
|
||||||
|
import java.util.AbstractMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.apache.poi.util.Internal;
|
||||||
|
import org.apache.poi.util.LocaleID;
|
||||||
|
import org.apache.poi.util.SuppressForbidden;
|
||||||
|
|
||||||
|
@Internal
|
||||||
|
public final class LocaleDateFormat {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum to specify initial remapping of the FormatID based on thd LCID
|
||||||
|
*/
|
||||||
|
public enum MapFormatId {
|
||||||
|
NONE, PPT
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum MapFormatPPT {
|
||||||
|
EN_US(LocaleID.EN_US, "MM/dd/yyyy", 1, 8, "MMMM dd, yyyy", 5, 9, 10, 11, 12, 15, 16, "h:mm a", "h:mm:ss a"),
|
||||||
|
EN_AU(LocaleID.EN_AU, 0, 1, "d MMMM, yyy", 2, 5, 9, 10, 11, 12, 15, 16, 13, 14),
|
||||||
|
JA_JP(LocaleID.JA_JP, 4, 8, 7, 3, 0, 9, 5, 11, 12, "HH:mm", "HH:mm:ss", 15, 16),
|
||||||
|
ZH_TW(LocaleID.ZH_TW, 0, 1, 3, 7, 12, 9, 10, 4, 11, "HH:mm", "HH:mm:ss", "H:mm a", "H:mm:ss a"),
|
||||||
|
KO_KR(LocaleID.KO_KR, 0, 1, 6, 3, 4, 10, 7, 12, 11, "HH:mm", "HH:mm:ss", 13, 14 ),
|
||||||
|
AR_SA(LocaleID.AR_SA, 0, 1, 2, 3, 4, 5, 8, 7, 8, 1, 10, 11, 5),
|
||||||
|
HE_IL(LocaleID.HE_IL, 0, 1, 2, 6, 11, 5, 12, 7, 8, 9, 1, 11, 6),
|
||||||
|
SV_SE(LocaleID.SV_SE, 0, 1, 3, 2, 7, 9, 10, 11, 12, 15, 16, 13, 14),
|
||||||
|
ZH_CN(LocaleID.ZH_CN, 0, 1, 2, 2, 4, 9, 5, "yyyy\u5E74M\u6708d\u65E5h\u65F6m\u5206", "yyyy\u5E74M\u6708d\u65E5\u661F\u671fWh\u65F6m\u5206s\u79D2", "HH:mm", "HH:mm:ss", "a h\u65F6m\u5206", "a h\u65F6m\u5206s\u79D2"),
|
||||||
|
ZH_SG(LocaleID.ZH_SG, 0, 1, 3, 2, 4, 9, 5, "yyyy\u5E74M\u6708d\u65E5h\u65F6m\u5206", "yyyy\u5E74M\u6708d\u65E5\u661F\u671fWh\u65F6m\u5206s\u79D2", "HH:mm", "HH:mm:ss", "a h\u65F6m\u5206", "a h\u65F6m\u5206s\u79D2"),
|
||||||
|
ZH_MO(LocaleID.ZH_MO, 0, 1, 3, 2, 4, 9, 5, "yyyy\u5E74M\u6708d\u65E5h\u65F6m\u5206", "yyyy\u5E74M\u6708d\u65E5\u661F\u671fWh\u65F6m\u5206s\u79D2", "HH:mm", "HH:mm:ss", "a h\u65F6m\u5206", "a h\u65F6m\u5206s\u79D2"),
|
||||||
|
ZH_HK(LocaleID.ZH_HK, 0, 1, 3, 2, 4, 9, 5, "yyyy\u5E74M\u6708d\u65E5h\u65F6m\u5206", "yyyy\u5E74M\u6708d\u65E5\u661F\u671fWh\u65F6m\u5206s\u79D2", "HH:mm", "HH:mm:ss", "a h\u65F6m\u5206", "a h\u65F6m\u5206s\u79D2"),
|
||||||
|
TH_TH(LocaleID.TH_TH, 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 13, 14),
|
||||||
|
VI_VN(LocaleID.VI_VN, 0, 1, 2, 3, 5, 6, 10, 11, 12, 13, 14, 15, 16),
|
||||||
|
HI_IN(LocaleID.HI_IN, 1, 2, 3, 5, 7, 11, 13, 0, 1, 5, 10, 11, 14),
|
||||||
|
SYR_SY(LocaleID.SYR_SY, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
|
||||||
|
NO_MAP(LocaleID.INVALID_O, 0, 1, 3, 2, 5, 9, 10, 11, 12, 15, 16, 13, 14, 4, 6, 7, 8)
|
||||||
|
;
|
||||||
|
|
||||||
|
private final LocaleID lcid;
|
||||||
|
private final Object[] mapping;
|
||||||
|
|
||||||
|
private static final Map<LocaleID,MapFormatPPT> LCID_LOOKUP =
|
||||||
|
Stream.of(values()).collect(Collectors.toMap(MapFormatPPT::getLocaleID, Function.identity()));
|
||||||
|
|
||||||
|
MapFormatPPT(LocaleID lcid, Object... mapping) {
|
||||||
|
this.lcid = lcid;
|
||||||
|
this.mapping = mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocaleID getLocaleID() {
|
||||||
|
return lcid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object mapFormatId(LocaleID lcid, int formatId) {
|
||||||
|
Object[] mapping = LCID_LOOKUP.getOrDefault(lcid, NO_MAP).mapping;
|
||||||
|
return (formatId >= 0 && formatId < mapping.length) ? mapping[formatId] : formatId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum MapFormatException {
|
||||||
|
CHINESE(
|
||||||
|
new LocaleID[]{LocaleID.ZH, LocaleID.ZH_HANS, LocaleID.ZH_HANT, LocaleID.ZH_CN, LocaleID.ZH_SG, LocaleID.ZH_MO, LocaleID.ZH_HK, LocaleID.ZH_YUE_HK},
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
"yyyy\u5E74M\u6708d\u65E5\u661F\u671FW",
|
||||||
|
"yyyy\u5E74M\u6708d\u65E5",
|
||||||
|
"yyyy/M/d",
|
||||||
|
"yy.M.d",
|
||||||
|
"yyyy\u5E74M\u6708d\u65E5\u661F\u671FW",
|
||||||
|
"yyyy\u5E74M\u6708d\u65E5",
|
||||||
|
"yyyy\u5E74M\u6708d\u65E5\u661F\u671FW",
|
||||||
|
"yyyy\u5E74M\u6708",
|
||||||
|
"yyyy\u5E74M\u6708",
|
||||||
|
"h\u65F6m\u5206s\u79D2",
|
||||||
|
"h\u65F6m\u5206",
|
||||||
|
"h\u65F6m\u5206",
|
||||||
|
"h\u65F6m\u5206",
|
||||||
|
"ah\u65F6m\u5206",
|
||||||
|
"ah\u65F6m\u5206",
|
||||||
|
// no lunar calendar support
|
||||||
|
"EEEE\u5E74O\u6708A\u65E5",
|
||||||
|
"EEEE\u5E74O\u6708A\u65E5\u661F\u671FW",
|
||||||
|
"EEEE\u5E74O\u6708"
|
||||||
|
),
|
||||||
|
// no hindu calendar support
|
||||||
|
HINDI(
|
||||||
|
new LocaleID[]{LocaleID.HI, LocaleID.HI_IN},
|
||||||
|
"dd/M/g",
|
||||||
|
"dddd, d MMMM yyyy",
|
||||||
|
"dd MMMM yyyy",
|
||||||
|
"dd/M/yy",
|
||||||
|
"yy-M-dd",
|
||||||
|
"d-MMMM-yyyy",
|
||||||
|
"dd.M.g",
|
||||||
|
"dd MMMM. yy",
|
||||||
|
"dd MMMM yy",
|
||||||
|
"MMMM YY",
|
||||||
|
"MMMM-g",
|
||||||
|
"dd/M/g HH:mm",
|
||||||
|
"dd/M/g HH:mm:ss",
|
||||||
|
"HH:mm a",
|
||||||
|
"HH:mm:ss a",
|
||||||
|
"HH:mm",
|
||||||
|
"HH:mm:ss"
|
||||||
|
),
|
||||||
|
// https://www.secondsite8.com/customdateformats.htm
|
||||||
|
// aa or gg or o, r, i, c -> lunar calendar not supported
|
||||||
|
// (aaa) -> lower case week names ... not supported
|
||||||
|
JAPANESE(
|
||||||
|
new LocaleID[]{LocaleID.JA, LocaleID.JA_JP, LocaleID.JA_PLOC_JP},
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
"EEEy\u5E74M\u6708d\u65E5",
|
||||||
|
"yyyy\u5E74M\u6708d\u65E5",
|
||||||
|
"yyyy/M/d",
|
||||||
|
"yyyy\u5E74M\u6708d\u65E5",
|
||||||
|
"yy\u5E74M\u6708d\u65E5",
|
||||||
|
"yyyy\u5E74M\u6708d\u65E5",
|
||||||
|
"yyyy\u5E74M\u6708d\u65E5(EEE)",
|
||||||
|
"yyyy\u5E74M\u6708",
|
||||||
|
"yyyy\u5E74M\u6708",
|
||||||
|
"yy/M/d H\u6642m\u5206",
|
||||||
|
"yy/M/d H\u6642m\u5206s\u79D2",
|
||||||
|
"a h\u6642m\u5206",
|
||||||
|
"a h\u6642m\u5206s\u79D2",
|
||||||
|
"H\u6642m\u5206",
|
||||||
|
"H\u6642m\u5206s\u79D2",
|
||||||
|
"yyyy\u5E74M\u6708d\u65E5 EEE\u66DC\u65E5"
|
||||||
|
),
|
||||||
|
KOREAN(
|
||||||
|
new LocaleID[]{LocaleID.KO,LocaleID.KO_KR},
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
"yyyy\uB144 M\uC6D4 d\uC77C EEE\uC694\uC77C",
|
||||||
|
"yyyy\uB144 M\uC6D4 d\uC77C",
|
||||||
|
"yyyy/M/d",
|
||||||
|
"yyMMdd",
|
||||||
|
"yyyy\uB144 M\uC6D4 d\uC77C",
|
||||||
|
"yyyy\uB144 M\uC6D4",
|
||||||
|
"yyyy\uB144 M\uC6D4 d\uC77C",
|
||||||
|
"yyyy",
|
||||||
|
"yyyy\uB144 M\uC6D4",
|
||||||
|
"yyyy\uB144 M\uC6D4 d\uC77C a h\uC2DC m\uBD84",
|
||||||
|
"yy\uB144 M\uC6D4 d\uC77C H\uC2DC m\uBD84 s\uCD08",
|
||||||
|
"a h\uC2DC m\uBD84",
|
||||||
|
"a h\uC2DC m\uBD84 s\uCD08",
|
||||||
|
"H\uC2DC m\uBD84",
|
||||||
|
"H\uC2DC m\uBD84 S\uCD08"
|
||||||
|
),
|
||||||
|
HUNGARIAN(
|
||||||
|
new LocaleID[]{LocaleID.HU, LocaleID.HU_HU},
|
||||||
|
0, 1, 2, 3, 4, 5, 6, "yy. MMM. dd.", "\u2019yy MMM.", "MMMM \u2019yy", 10, 11, 12, "a h:mm", "a h:mm:ss", 15, 16
|
||||||
|
),
|
||||||
|
BOKMAL(
|
||||||
|
new LocaleID[]{LocaleID.NB_NO},
|
||||||
|
0, 1, 2, 3, 4, "d. MMM. yyyy", "d/m yyyy", "MMM. yy", "yyyy.mm.dd", 9, "d. MMM.", 11, 12, 13, 14, 15, 16
|
||||||
|
),
|
||||||
|
CZECH(new LocaleID[]{LocaleID.CS, LocaleID.CS_CZ}, 0, 1, 2, 3, 4, 5, 6, 7, 8, "MMMM \u2019yy", 10, 11, 12, 13, 14, 15, 16),
|
||||||
|
DANISH(new LocaleID[]{LocaleID.DA, LocaleID.DA_DK}, 0, "d. MMMM yyyy", "yy-MM-dd", "yyyy.MM.dd", 4, "MMMM yyyy", "d.M.yy", "d/M yyyy", "dd.MM.yyyy", "d.M.yyyy", "dd/MM yyyy", 11, 12, 13, 14, 15, 16 ),
|
||||||
|
DUTCH(new LocaleID[]{LocaleID.NL,LocaleID.NL_BE,LocaleID.NL_NL}, 0, 1, 2, 3, 4, 5, 6, 7, 8, "MMMM \u2019yy", 10, 11, 12, 13, 14, 15, 16),
|
||||||
|
FINISH(new LocaleID[]{LocaleID.FI, LocaleID.FI_FI}, 0, 1, 2, 3, 4, 5, 6, 7, 8, "MMMM \u2019yy", 10, 11, 12, 13, 14, 15, 16),
|
||||||
|
FRENCH_CANADIAN(new LocaleID[]{LocaleID.FR_CA}, 0, 1, 2, "yy MM dd", 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16),
|
||||||
|
GERMAN(new LocaleID[]{LocaleID.DE,LocaleID.DE_AT,LocaleID.DE_CH,LocaleID.DE_DE,LocaleID.DE_LI,LocaleID.DE_LU}, 0, 1, 2, 3, 4, "yy-MM-dd", 6, "dd. MMM. yyyy", 8, 9, 10, 11, 12, 13, 14, 15, 16),
|
||||||
|
ITALIAN(new LocaleID[]{LocaleID.IT,LocaleID.IT_IT,LocaleID.IT_CH}, 0, 1, 2, 3, 4, "d-MMM.-yy", 6, "d. MMM. yy", "MMM. \u2019yy", "MMMM \u2019yy", 10, 11, 12, 13, 14, 15, 16),
|
||||||
|
NO_MAP(new LocaleID[]{LocaleID.INVALID_O}, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
|
||||||
|
// TODO: add others from [MS-OSHARED] chapter 2.4.4.4
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
private final LocaleID[] lcid;
|
||||||
|
private final Object[] mapping;
|
||||||
|
|
||||||
|
private static final Map<LocaleID, MapFormatException> LCID_LOOKUP =
|
||||||
|
Stream.of(values()).flatMap(m -> Stream.of(m.lcid).map(l -> new AbstractMap.SimpleEntry<>(l, m)))
|
||||||
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||||
|
|
||||||
|
MapFormatException(LocaleID[] lcid, Object... mapping) {
|
||||||
|
this.lcid = lcid;
|
||||||
|
this.mapping = mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object mapFormatId(LocaleID lcid, int formatId) {
|
||||||
|
Object[] mapping = LCID_LOOKUP.getOrDefault(lcid, NO_MAP).mapping;
|
||||||
|
return (formatId >= 0 && formatId < mapping.length) ? mapping[formatId] : formatId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This enum lists and describes the format indices that can be used as inputs to the algorithm. The
|
||||||
|
* descriptions given are generalized; the actual format produced can vary from the description,
|
||||||
|
* depending on the input locale.
|
||||||
|
*/
|
||||||
|
@SuppressForbidden("DateTimeFormatter::ofLocalizedDate and others will be localized in mapFormatId")
|
||||||
|
private enum MapFormatBase {
|
||||||
|
/** 0 - Base short date **/
|
||||||
|
SHORT_DATE(null, FormatStyle.MEDIUM, DateTimeFormatter::ofLocalizedDate),
|
||||||
|
/** 1 - Base long date. **/
|
||||||
|
LONG_DATE(null, FormatStyle.FULL, DateTimeFormatter::ofLocalizedDate),
|
||||||
|
/**
|
||||||
|
* 2 - Do the following to base long date:
|
||||||
|
* - Remove occurrences of "dddd".
|
||||||
|
* - Remove the comma symbol (0x002C) and space following "dddd" if present.
|
||||||
|
* - Change occurrences of "dd" to "d".
|
||||||
|
**/
|
||||||
|
LONG_DATE_WITHOUT_WEEKDAY("d. MMMM yyyy", null, null),
|
||||||
|
/**
|
||||||
|
* 3 - Do the following to base short date:
|
||||||
|
* - Change occurrences of "yyyy" to "yy".
|
||||||
|
* - Change occurrences of "yy" to "yyyy".
|
||||||
|
*/
|
||||||
|
ALTERNATE_SHORT_DATE("dd/MM/yy", null, null),
|
||||||
|
/**
|
||||||
|
* 4 - yyyy-MM-dd
|
||||||
|
*/
|
||||||
|
ISO_STANDARD_DATE("yyyy-MM-dd", null, null),
|
||||||
|
/**
|
||||||
|
* 5 - If the symbol "y" occurs before the symbol "M" occurs in the base short date, the format is
|
||||||
|
* "yy-MMM-d". Otherwise, the format is "d-MMM-yy".
|
||||||
|
*/
|
||||||
|
SHORT_DATE_WITH_ABBREVIATED_MONTH("d-MMM-yy", null, null),
|
||||||
|
/**
|
||||||
|
* 6 - If the forward slash symbol (0x002F) occurs in the base short date, the slash symbol is the
|
||||||
|
* period symbol (0x002E). Otherwise, the slash symbol is the forward slash (0x002F).
|
||||||
|
* A group is an uninterrupted sequence of qualified symbols where a qualified symbol is "d",
|
||||||
|
* "M", or "Y".
|
||||||
|
* Identify the first three groups that occur in the base short date. The format is formed by
|
||||||
|
* appending the three groups together with single slash symbols separating the groups.
|
||||||
|
*/
|
||||||
|
SHORT_DATE_WITH_SLASHES("d/M/y", null, null),
|
||||||
|
/**
|
||||||
|
* 7 - Do the following to base long date:
|
||||||
|
* - Remove occurrences of "dddd".
|
||||||
|
* - Remove the comma symbol (0x002C) and space following "dddd" if present.
|
||||||
|
* - Change occurrences of "dd" to "d".
|
||||||
|
* - For all right-to-left locales and Lao, change a sequence of any length of "M" to "MMM".
|
||||||
|
* - For all other locales, change a sequence of any length of "M" to "MMM".
|
||||||
|
* - Change occurrences of "yyyy" to "yy".
|
||||||
|
*/
|
||||||
|
ALTERNATE_SHORT_DATE_WITH_ABBREVIATED_MONTH("d. MMM yy", null, null),
|
||||||
|
/**
|
||||||
|
* 8 - For American English and Arabic, the format is "d MMMM yyyy".
|
||||||
|
* For Hebrew, the format is "d MMMM, yyyy".
|
||||||
|
* For all other locales, the format is the same as format 6 with the following additional step:
|
||||||
|
* Change occurrences of "yyyy" to "yy".
|
||||||
|
*/
|
||||||
|
ENGLISH_DATE("d MMMM yyyy", null, null),
|
||||||
|
/**
|
||||||
|
* 9 - Do the following to base long date:
|
||||||
|
* - Remove all symbols that occur before the first occurrence of either the "y" symbol or the "M" symbol.
|
||||||
|
* - Remove all "d" symbols.
|
||||||
|
* - For all locales except Lithuanian, remove all period symbols (0x002E).
|
||||||
|
* - Remove all comma symbols (0x002C).
|
||||||
|
* - Change occurrences of "yyyy" to "yy".
|
||||||
|
*/
|
||||||
|
MONTH_AND_YEAR("MMMM yy", null, null),
|
||||||
|
/**
|
||||||
|
* 10 - MMM-yy
|
||||||
|
*/
|
||||||
|
ABBREVIATED_MONTH_AND_YEAR("LLL-yy", null, null),
|
||||||
|
/**
|
||||||
|
* 11 - Base short date followed by a space, followed by base time with seconds removed.
|
||||||
|
* Seconds are removed by removing all "s" symbols and any symbol that directly precedes an
|
||||||
|
* "s" symbol that is not an "h" or "m" symbol.
|
||||||
|
*/
|
||||||
|
DATE_AND_HOUR12_TIME(null, FormatStyle.MEDIUM, (fs) -> new DateTimeFormatterBuilder().appendLocalized(FormatStyle.SHORT, null).appendLiteral(" ").appendLocalized(null, FormatStyle.SHORT).toFormatter()),
|
||||||
|
/**
|
||||||
|
* 12 - Base short date followed by a space, followed by base time.
|
||||||
|
*/
|
||||||
|
DATE_AND_HOUR12_TIME_WITH_SECONDS(null, FormatStyle.MEDIUM, (fs) -> new DateTimeFormatterBuilder().appendLocalized(FormatStyle.SHORT, null).appendLiteral(" ").appendLocalized(null, fs).toFormatter()),
|
||||||
|
/**
|
||||||
|
* 13 - For Hungarian, the format is "am/pm h:mm".
|
||||||
|
* For all other locales, the format is "h:mm am/pm".
|
||||||
|
* In both cases, replace occurrences of the colon symbol (0x003A) with the time separator.
|
||||||
|
*/
|
||||||
|
HOUR12_TIME("K:mm", null, null),
|
||||||
|
/**
|
||||||
|
* 14 - For Hungarian, the format is "am/pm h:mm:ss".
|
||||||
|
* For all other locales, the format is "h:mm:ss am/pm".
|
||||||
|
* In both cases, replace occurrences of the colon symbol (0x003A) with the time separator.
|
||||||
|
*/
|
||||||
|
HOUR12_TIME_WITH_SECONDS("K:mm:ss", null, null),
|
||||||
|
/**
|
||||||
|
* 15 - "HH" followed by the time separator, followed by "mm".
|
||||||
|
*/
|
||||||
|
HOUR24_TIME("HH:mm", null, null),
|
||||||
|
/**
|
||||||
|
* 16 - "HH" followed by the time separator, followed by "mm", followed by the time separator
|
||||||
|
* followed by "ss".
|
||||||
|
*/
|
||||||
|
HOUR24_TIME_WITH_SECONDS("HH:mm:ss", null, null),
|
||||||
|
// CHINESE1(null, null, null),
|
||||||
|
// CHINESE2(null, null, null),
|
||||||
|
// CHINESE3(null, null, null)
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
private final String datefmt;
|
||||||
|
private final FormatStyle formatStyle;
|
||||||
|
private final Function<FormatStyle,DateTimeFormatter> formatFct;
|
||||||
|
|
||||||
|
MapFormatBase(String datefmt, FormatStyle formatStyle, Function<FormatStyle,DateTimeFormatter> formatFct) {
|
||||||
|
this.formatStyle = formatStyle;
|
||||||
|
this.datefmt = datefmt;
|
||||||
|
this.formatFct = formatFct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTimeFormatter mapFormatId(Locale loc, int formatId) {
|
||||||
|
MapFormatBase[] mfb = MapFormatBase.values();
|
||||||
|
if (formatId < 0 || formatId >= mfb.length) {
|
||||||
|
return DateTimeFormatter.BASIC_ISO_DATE;
|
||||||
|
}
|
||||||
|
MapFormatBase mf = mfb[formatId];
|
||||||
|
return (mf.datefmt == null)
|
||||||
|
? mf.formatFct.apply(mf.formatStyle).withLocale(loc)
|
||||||
|
: DateTimeFormatter.ofPattern(mf.datefmt, loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocaleDateFormat() {}
|
||||||
|
|
||||||
|
public static DateTimeFormatter map(LocaleID lcid, int formatID, MapFormatId mapFormatId) {
|
||||||
|
final Locale loc = Locale.forLanguageTag(lcid.getLanguageTag());
|
||||||
|
int mappedFormatId = formatID;
|
||||||
|
if (mapFormatId == MapFormatId.PPT) {
|
||||||
|
Object mappedFormat = MapFormatPPT.mapFormatId(lcid, formatID);
|
||||||
|
if (mappedFormat instanceof String) {
|
||||||
|
return DateTimeFormatter.ofPattern((String)mappedFormat,loc);
|
||||||
|
} else {
|
||||||
|
mappedFormatId = (Integer)mappedFormat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object mappedFormat = MapFormatException.mapFormatId(lcid, mappedFormatId);
|
||||||
|
if (mappedFormat instanceof String) {
|
||||||
|
return DateTimeFormatter.ofPattern((String)mappedFormat,loc);
|
||||||
|
} else {
|
||||||
|
return MapFormatBase.mapFormatId(loc, (Integer)mappedFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,8 +17,10 @@
|
||||||
|
|
||||||
package org.apache.poi.hslf.usermodel;
|
package org.apache.poi.hslf.usermodel;
|
||||||
|
|
||||||
import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor;
|
import static org.apache.poi.hslf.HSLFTestDataSamples.getSlideShow;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
@ -27,15 +29,22 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.apache.poi.hslf.HSLFTestDataSamples;
|
import org.apache.poi.hslf.HSLFTestDataSamples;
|
||||||
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
||||||
|
import org.apache.poi.hslf.record.DateTimeMCAtom;
|
||||||
import org.apache.poi.hslf.record.TextBytesAtom;
|
import org.apache.poi.hslf.record.TextBytesAtom;
|
||||||
import org.apache.poi.hslf.record.TextCharsAtom;
|
import org.apache.poi.hslf.record.TextCharsAtom;
|
||||||
import org.apache.poi.hslf.record.TextHeaderAtom;
|
import org.apache.poi.sl.usermodel.BaseTestSlideShow;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.apache.poi.sl.usermodel.PlaceholderDetails;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.apache.poi.util.LocaleUtil;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,62 +52,47 @@ import org.junit.jupiter.api.Test;
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("UnusedAssignment")
|
@SuppressWarnings("UnusedAssignment")
|
||||||
public final class TestTextRun {
|
public final class TestTextRun {
|
||||||
// SlideShow primed on the test data
|
|
||||||
private HSLFSlideShow ss;
|
|
||||||
private HSLFSlideShow ssRich;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() throws IOException {
|
|
||||||
// Basic (non rich) test file
|
|
||||||
ss = HSLFTestDataSamples.getSlideShow("basic_test_ppt_file.ppt");
|
|
||||||
|
|
||||||
// Rich test file
|
|
||||||
ssRich = HSLFTestDataSamples.getSlideShow("Single_Coloured_Page.ppt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
void tearDown() throws IOException {
|
|
||||||
ssRich.close();
|
|
||||||
ss.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test to ensure that getting the text works correctly
|
* Test to ensure that getting the text works correctly
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testGetText() {
|
void testGetText() throws IOException {
|
||||||
HSLFSlide slideOne = ss.getSlides().get(0);
|
try (HSLFSlideShow ppt = getSlideShow("basic_test_ppt_file.ppt")) {
|
||||||
|
HSLFSlide slideOne = ppt.getSlides().get(0);
|
||||||
List<List<HSLFTextParagraph>> textParas = slideOne.getTextParagraphs();
|
List<List<HSLFTextParagraph>> textParas = slideOne.getTextParagraphs();
|
||||||
|
|
||||||
assertEquals(2, textParas.size());
|
|
||||||
|
|
||||||
// Get text works with \n
|
// Get text works with \n
|
||||||
assertEquals("This is a test title", HSLFTextParagraph.getText(textParas.get(0)));
|
String[] exp1 = { "This is a test title", "This is a test subtitle\nThis is on page 1" };
|
||||||
assertEquals("This is a test subtitle\nThis is on page 1", HSLFTextParagraph.getText(textParas.get(1)));
|
String[] act1 = textParas.stream().map(HSLFTextParagraph::getText).toArray(String[]::new);
|
||||||
|
assertArrayEquals(exp1, act1);
|
||||||
|
|
||||||
// Raw text has \r instead
|
// Raw text has \r instead
|
||||||
assertEquals("This is a test title", HSLFTextParagraph.getRawText(textParas.get(0)));
|
String[] exp2 = { "This is a test title", "This is a test subtitle\rThis is on page 1" };
|
||||||
assertEquals("This is a test subtitle\rThis is on page 1", HSLFTextParagraph.getRawText(textParas.get(1)));
|
String[] act2 = textParas.stream().map(HSLFTextParagraph::getRawText).toArray(String[]::new);
|
||||||
|
assertArrayEquals(exp2, act2);
|
||||||
|
}
|
||||||
|
|
||||||
// Now check on a rich text run
|
// Now check on a rich text run
|
||||||
HSLFSlide slideOneR = ssRich.getSlides().get(0);
|
try (HSLFSlideShow ppt = getSlideShow("Single_Coloured_Page.ppt")) {
|
||||||
textParas = slideOneR.getTextParagraphs();
|
List<List<HSLFTextParagraph>> textParas = ppt.getSlides().get(0).getTextParagraphs();
|
||||||
|
|
||||||
assertEquals(2, textParas.size());
|
String[] exp1 = { "This is a title, it\u2019s in black", "This is the subtitle, in bold\nThis bit is blue and italic\nThis bit is red (normal)" };
|
||||||
assertEquals("This is a title, it\u2019s in black", HSLFTextParagraph.getText(textParas.get(0)));
|
String[] act1 = textParas.stream().map(HSLFTextParagraph::getText).toArray(String[]::new);
|
||||||
assertEquals("This is the subtitle, in bold\nThis bit is blue and italic\nThis bit is red (normal)", HSLFTextParagraph.getText(textParas.get(1)));
|
assertArrayEquals(exp1, act1);
|
||||||
assertEquals("This is a title, it\u2019s in black", HSLFTextParagraph.getRawText(textParas.get(0)));
|
|
||||||
assertEquals("This is the subtitle, in bold\rThis bit is blue and italic\rThis bit is red (normal)", HSLFTextParagraph.getRawText(textParas.get(1)));
|
String[] exp2 = { "This is a title, it\u2019s in black", "This is the subtitle, in bold\rThis bit is blue and italic\rThis bit is red (normal)" };
|
||||||
|
String[] act2 = textParas.stream().map(HSLFTextParagraph::getRawText).toArray(String[]::new);
|
||||||
|
assertArrayEquals(exp2, act2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test to ensure changing non rich text bytes->bytes works correctly
|
* Test to ensure changing non rich text bytes->bytes works correctly
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testSetText() {
|
void testSetText() throws IOException {
|
||||||
HSLFSlide slideOne = ss.getSlides().get(0);
|
try (HSLFSlideShow ppt = getSlideShow("basic_test_ppt_file.ppt")) {
|
||||||
List<List<HSLFTextParagraph>> textRuns = slideOne.getTextParagraphs();
|
List<List<HSLFTextParagraph>> textRuns = ppt.getSlides().get(0).getTextParagraphs();
|
||||||
HSLFTextParagraph run = textRuns.get(0).get(0);
|
HSLFTextParagraph run = textRuns.get(0).get(0);
|
||||||
HSLFTextRun tr = run.getTextRuns().get(0);
|
HSLFTextRun tr = run.getTextRuns().get(0);
|
||||||
|
|
||||||
|
@ -114,6 +108,7 @@ public final class TestTextRun {
|
||||||
tr.setText(changeTo + "\n");
|
tr.setText(changeTo + "\n");
|
||||||
assertEquals(changeTo + "\r", tr.getRawText());
|
assertEquals(changeTo + "\r", tr.getRawText());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test to ensure that changing non rich text between bytes and
|
* Test to ensure that changing non rich text between bytes and
|
||||||
|
@ -121,74 +116,53 @@ public final class TestTextRun {
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Test
|
@Test
|
||||||
void testAdvancedSetText() {
|
void testAdvancedSetText() throws IOException {
|
||||||
HSLFSlide slideOne = ss.getSlides().get(0);
|
try (HSLFSlideShow ppt = getSlideShow("basic_test_ppt_file.ppt")) {
|
||||||
List<HSLFTextParagraph> paras = slideOne.getTextParagraphs().get(0);
|
List<HSLFTextParagraph> paras = ppt.getSlides().get(0).getTextParagraphs().get(0);
|
||||||
HSLFTextParagraph para = paras.get(0);
|
final HSLFTextParagraph para = paras.get(0);
|
||||||
|
|
||||||
TextHeaderAtom tha = null;
|
final TextBytesAtom[] tba = { null };
|
||||||
TextBytesAtom tba = null;
|
final TextCharsAtom[] tca = { null };
|
||||||
TextCharsAtom tca = null;
|
Runnable extract = () -> {
|
||||||
for ( org.apache.poi.hslf.record.Record r : para.getRecords()) {
|
tba[0] = null;
|
||||||
if (r instanceof TextHeaderAtom) tha = (TextHeaderAtom)r;
|
tca[0] = null;
|
||||||
else if (r instanceof TextBytesAtom) tba = (TextBytesAtom)r;
|
Stream.of(para.getRecords()).forEach(r -> {
|
||||||
else if (r instanceof TextCharsAtom) tca = (TextCharsAtom)r;
|
if (r instanceof TextBytesAtom) tba[0] = (TextBytesAtom) r;
|
||||||
}
|
else if (r instanceof TextCharsAtom) tca[0] = (TextCharsAtom) r;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Bytes -> Bytes
|
// Bytes -> Bytes
|
||||||
assertNull(tca);
|
extract.run();
|
||||||
|
assertNull(tca[0]);
|
||||||
assertNotNull(tba);
|
assertNotNull(tba);
|
||||||
// assertFalse(run._isUnicode);
|
// assertFalse(run._isUnicode);
|
||||||
assertEquals("This is a test title", para.getTextRuns().get(0).getRawText());
|
assertEquals("This is a test title", para.getTextRuns().get(0).getRawText());
|
||||||
|
|
||||||
String changeBytesOnly = "New Test Title";
|
String changeBytesOnly = "New Test Title";
|
||||||
HSLFTextParagraph.setText(paras, changeBytesOnly);
|
HSLFTextParagraph.setText(paras, changeBytesOnly);
|
||||||
para = paras.get(0);
|
extract.run();
|
||||||
tha = null; tba = null; tca = null;
|
|
||||||
for ( org.apache.poi.hslf.record.Record r : para.getRecords()) {
|
|
||||||
if (r instanceof TextHeaderAtom) tha = (TextHeaderAtom)r;
|
|
||||||
else if (r instanceof TextBytesAtom) tba = (TextBytesAtom)r;
|
|
||||||
else if (r instanceof TextCharsAtom) tca = (TextCharsAtom)r;
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(changeBytesOnly, HSLFTextParagraph.getRawText(paras));
|
assertEquals(changeBytesOnly, HSLFTextParagraph.getRawText(paras));
|
||||||
assertNull(tca);
|
assertNull(tca[0]);
|
||||||
assertNotNull(tba);
|
assertNotNull(tba);
|
||||||
|
|
||||||
// Bytes -> Chars
|
// Bytes -> Chars
|
||||||
assertEquals(changeBytesOnly, HSLFTextParagraph.getRawText(paras));
|
|
||||||
|
|
||||||
String changeByteChar = "This is a test title with a '\u0121' g with a dot";
|
String changeByteChar = "This is a test title with a '\u0121' g with a dot";
|
||||||
HSLFTextParagraph.setText(paras, changeByteChar);
|
HSLFTextParagraph.setText(paras, changeByteChar);
|
||||||
para = paras.get(0);
|
extract.run();
|
||||||
tha = null; tba = null; tca = null;
|
|
||||||
for ( org.apache.poi.hslf.record.Record r : para.getRecords()) {
|
|
||||||
if (r instanceof TextHeaderAtom) tha = (TextHeaderAtom)r;
|
|
||||||
else if (r instanceof TextBytesAtom) tba = (TextBytesAtom)r;
|
|
||||||
else if (r instanceof TextCharsAtom) tca = (TextCharsAtom)r;
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(changeByteChar, HSLFTextParagraph.getRawText(paras));
|
assertEquals(changeByteChar, HSLFTextParagraph.getRawText(paras));
|
||||||
assertNotNull(tca);
|
assertNotNull(tca[0]);
|
||||||
assertNull(tba);
|
assertNull(tba[0]);
|
||||||
|
|
||||||
// Chars -> Chars
|
// Chars -> Chars
|
||||||
assertNotNull(tca);
|
|
||||||
assertEquals(changeByteChar, HSLFTextParagraph.getRawText(paras));
|
|
||||||
|
|
||||||
String changeCharChar = "This is a test title with a '\u0147' N with a hat";
|
String changeCharChar = "This is a test title with a '\u0147' N with a hat";
|
||||||
HSLFTextParagraph.setText(paras, changeCharChar);
|
HSLFTextParagraph.setText(paras, changeCharChar);
|
||||||
para = paras.get(0);
|
extract.run();
|
||||||
tha = null; tba = null; tca = null;
|
|
||||||
for ( org.apache.poi.hslf.record.Record r : para.getRecords()) {
|
|
||||||
if (r instanceof TextHeaderAtom) tha = (TextHeaderAtom)r;
|
|
||||||
else if (r instanceof TextBytesAtom) tba = (TextBytesAtom)r;
|
|
||||||
else if (r instanceof TextCharsAtom) tca = (TextCharsAtom)r;
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(changeCharChar, HSLFTextParagraph.getRawText(paras));
|
assertEquals(changeCharChar, HSLFTextParagraph.getRawText(paras));
|
||||||
assertNotNull(tca);
|
assertNotNull(tca[0]);
|
||||||
assertNull(tba);
|
assertNull(tba[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -196,9 +170,9 @@ public final class TestTextRun {
|
||||||
* set up for it
|
* set up for it
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testGetRichTextNonRich() {
|
void testGetRichTextNonRich() throws IOException {
|
||||||
HSLFSlide slideOne = ss.getSlides().get(0);
|
try (HSLFSlideShow ppt = getSlideShow("basic_test_ppt_file.ppt")) {
|
||||||
List<List<HSLFTextParagraph>> textParass = slideOne.getTextParagraphs();
|
List<List<HSLFTextParagraph>> textParass = ppt.getSlides().get(0).getTextParagraphs();
|
||||||
|
|
||||||
assertEquals(2, textParass.size());
|
assertEquals(2, textParass.size());
|
||||||
|
|
||||||
|
@ -214,14 +188,15 @@ public final class TestTextRun {
|
||||||
assertEquals(HSLFTextParagraph.getRawText(trA), rtrA.getRawText());
|
assertEquals(HSLFTextParagraph.getRawText(trA), rtrA.getRawText());
|
||||||
assertEquals(HSLFTextParagraph.getRawText(trB.subList(0, 1)), rtrB.getRawText());
|
assertEquals(HSLFTextParagraph.getRawText(trB.subList(0, 1)), rtrB.getRawText());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests to ensure that the rich text runs are built up correctly
|
* Tests to ensure that the rich text runs are built up correctly
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testGetRichText() {
|
void testGetRichText() throws IOException {
|
||||||
HSLFSlide slideOne = ssRich.getSlides().get(0);
|
try (HSLFSlideShow ppt = getSlideShow("Single_Coloured_Page.ppt")) {
|
||||||
List<List<HSLFTextParagraph>> textParass = slideOne.getTextParagraphs();
|
List<List<HSLFTextParagraph>> textParass = ppt.getSlides().get(0).getTextParagraphs();
|
||||||
|
|
||||||
assertEquals(2, textParass.size());
|
assertEquals(2, textParass.size());
|
||||||
|
|
||||||
|
@ -252,16 +227,16 @@ public final class TestTextRun {
|
||||||
assertNotEquals(rtrB.getCharacterStyle(), rtrD.getCharacterStyle());
|
assertNotEquals(rtrB.getCharacterStyle(), rtrD.getCharacterStyle());
|
||||||
assertNotEquals(rtrC.getCharacterStyle(), rtrD.getCharacterStyle());
|
assertNotEquals(rtrC.getCharacterStyle(), rtrD.getCharacterStyle());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests to ensure that setting the text where the text isn't rich,
|
* Tests to ensure that setting the text where the text isn't rich,
|
||||||
* ensuring that everything stays with the same default styling
|
* ensuring that everything stays with the same default styling
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testSetTextWhereNotRich() {
|
void testSetTextWhereNotRich() throws IOException {
|
||||||
HSLFSlide slideOne = ss.getSlides().get(0);
|
try (HSLFSlideShow ppt = getSlideShow("basic_test_ppt_file.ppt")) {
|
||||||
List<List<HSLFTextParagraph>> textParass = slideOne.getTextParagraphs();
|
List<HSLFTextParagraph> trB = ppt.getSlides().get(0).getTextParagraphs().get(0);
|
||||||
List<HSLFTextParagraph> trB = textParass.get(0);
|
|
||||||
assertEquals(1, trB.size());
|
assertEquals(1, trB.size());
|
||||||
|
|
||||||
HSLFTextRun rtrB = trB.get(0).getTextRuns().get(0);
|
HSLFTextRun rtrB = trB.get(0).getTextRuns().get(0);
|
||||||
|
@ -273,16 +248,16 @@ public final class TestTextRun {
|
||||||
assertEquals("Test Foo Test", HSLFTextParagraph.getRawText(trB));
|
assertEquals("Test Foo Test", HSLFTextParagraph.getRawText(trB));
|
||||||
assertEquals("Test Foo Test", rtrB.getRawText());
|
assertEquals("Test Foo Test", rtrB.getRawText());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests to ensure that setting the text where the text is rich
|
* Tests to ensure that setting the text where the text is rich
|
||||||
* sets everything to the same styling
|
* sets everything to the same styling
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testSetTextWhereRich() {
|
void testSetTextWhereRich() throws IOException {
|
||||||
HSLFSlide slideOne = ssRich.getSlides().get(0);
|
try (HSLFSlideShow ppt = getSlideShow("Single_Coloured_Page.ppt")) {
|
||||||
List<List<HSLFTextParagraph>> textParass = slideOne.getTextParagraphs();
|
List<HSLFTextParagraph> trB = ppt.getSlides().get(0).getTextParagraphs().get(1);
|
||||||
List<HSLFTextParagraph> trB = textParass.get(1);
|
|
||||||
assertEquals(3, trB.size());
|
assertEquals(3, trB.size());
|
||||||
|
|
||||||
HSLFTextRun rtrB = trB.get(0).getTextRuns().get(0);
|
HSLFTextRun rtrB = trB.get(0).getTextRuns().get(0);
|
||||||
|
@ -322,15 +297,16 @@ public final class TestTextRun {
|
||||||
assertEquals(tpBP, rtrB.getTextParagraph().getParagraphStyle());
|
assertEquals(tpBP, rtrB.getTextParagraph().getParagraphStyle());
|
||||||
assertEquals(tpBC, rtrB.getCharacterStyle());
|
assertEquals(tpBC, rtrB.getCharacterStyle());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test to ensure the right stuff happens if we change the text
|
* Test to ensure the right stuff happens if we change the text
|
||||||
* in a rich text run, that doesn't happen to actually be rich
|
* in a rich text run, that doesn't happen to actually be rich
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testChangeTextInRichTextRunNonRich() {
|
void testChangeTextInRichTextRunNonRich() throws IOException {
|
||||||
HSLFSlide slideOne = ss.getSlides().get(0);
|
try (HSLFSlideShow ppt = getSlideShow("basic_test_ppt_file.ppt")) {
|
||||||
List<List<HSLFTextParagraph>> textRuns = slideOne.getTextParagraphs();
|
List<List<HSLFTextParagraph>> textRuns = ppt.getSlides().get(0).getTextParagraphs();
|
||||||
List<HSLFTextParagraph> trB = textRuns.get(1);
|
List<HSLFTextParagraph> trB = textRuns.get(1);
|
||||||
assertEquals(1, trB.get(0).getTextRuns().size());
|
assertEquals(1, trB.get(0).getTextRuns().size());
|
||||||
|
|
||||||
|
@ -348,14 +324,16 @@ public final class TestTextRun {
|
||||||
assertNotNull(rtrB.getCharacterStyle());
|
assertNotNull(rtrB.getCharacterStyle());
|
||||||
assertNotNull(rtrB.getTextParagraph().getParagraphStyle());
|
assertNotNull(rtrB.getTextParagraph().getParagraphStyle());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests to ensure changing the text within rich text runs works
|
* Tests to ensure changing the text within rich text runs works
|
||||||
* correctly
|
* correctly
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testChangeTextInRichTextRun() {
|
void testChangeTextInRichTextRun() throws IOException {
|
||||||
HSLFSlide slideOne = ssRich.getSlides().get(0);
|
try (HSLFSlideShow ppt = getSlideShow("Single_Coloured_Page.ppt")) {
|
||||||
|
HSLFSlide slideOne = ppt.getSlides().get(0);
|
||||||
List<List<HSLFTextParagraph>> textParass = slideOne.getTextParagraphs();
|
List<List<HSLFTextParagraph>> textParass = slideOne.getTextParagraphs();
|
||||||
List<HSLFTextParagraph> trB = textParass.get(1);
|
List<HSLFTextParagraph> trB = textParass.get(1);
|
||||||
assertEquals(3, trB.size());
|
assertEquals(3, trB.size());
|
||||||
|
@ -425,6 +403,7 @@ public final class TestTextRun {
|
||||||
assertEquals(tpCC.getTextPropList(), ntpCC.getTextPropList());
|
assertEquals(tpCC.getTextPropList(), ntpCC.getTextPropList());
|
||||||
assertEquals(tpDC.getTextPropList(), ntpDC.getTextPropList());
|
assertEquals(tpDC.getTextPropList(), ntpDC.getTextPropList());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -436,15 +415,13 @@ public final class TestTextRun {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testBug41015() throws IOException {
|
void testBug41015() throws IOException {
|
||||||
List<HSLFTextRun> rt;
|
try (HSLFSlideShow ppt = getSlideShow("bug-41015.ppt")) {
|
||||||
|
|
||||||
HSLFSlideShow ppt = HSLFTestDataSamples.getSlideShow("bug-41015.ppt");
|
|
||||||
HSLFSlide sl = ppt.getSlides().get(0);
|
HSLFSlide sl = ppt.getSlides().get(0);
|
||||||
List<List<HSLFTextParagraph>> textParass = sl.getTextParagraphs();
|
List<List<HSLFTextParagraph>> textParass = sl.getTextParagraphs();
|
||||||
assertEquals(2, textParass.size());
|
assertEquals(2, textParass.size());
|
||||||
|
|
||||||
List<HSLFTextParagraph> textParas = textParass.get(0);
|
List<HSLFTextParagraph> textParas = textParass.get(0);
|
||||||
rt = textParass.get(0).get(0).getTextRuns();
|
List<HSLFTextRun> rt = textParass.get(0).get(0).getTextRuns();
|
||||||
assertEquals(1, rt.size());
|
assertEquals(1, rt.size());
|
||||||
assertEquals(0, textParass.get(0).get(0).getIndentLevel());
|
assertEquals(0, textParass.get(0).get(0).getIndentLevel());
|
||||||
assertEquals("sdfsdfsdf", rt.get(0).getRawText());
|
assertEquals("sdfsdfsdf", rt.get(0).getRawText());
|
||||||
|
@ -458,7 +435,7 @@ public final class TestTextRun {
|
||||||
assertEquals(indents[i], p.getIndentLevel());
|
assertEquals(indents[i], p.getIndentLevel());
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
ppt.close();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -466,7 +443,7 @@ public final class TestTextRun {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testAddTextRun() throws IOException {
|
void testAddTextRun() throws IOException {
|
||||||
HSLFSlideShow ppt = new HSLFSlideShow();
|
try (HSLFSlideShow ppt = new HSLFSlideShow()) {
|
||||||
HSLFSlide slide = ppt.createSlide();
|
HSLFSlide slide = ppt.createSlide();
|
||||||
|
|
||||||
assertEquals(0, slide.getTextParagraphs().size());
|
assertEquals(0, slide.getTextParagraphs().size());
|
||||||
|
@ -509,12 +486,12 @@ public final class TestTextRun {
|
||||||
runs = slide2.getTextParagraphs();
|
runs = slide2.getTextParagraphs();
|
||||||
assertNotNull(runs);
|
assertNotNull(runs);
|
||||||
assertEquals(4, runs.size());
|
assertEquals(4, runs.size());
|
||||||
ppt.close();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test48916() throws IOException {
|
void test48916() throws IOException {
|
||||||
HSLFSlideShow ppt1 = HSLFTestDataSamples.getSlideShow("SampleShow.ppt");
|
try (HSLFSlideShow ppt1 = getSlideShow("SampleShow.ppt")) {
|
||||||
List<HSLFSlide> slides = ppt1.getSlides();
|
List<HSLFSlide> slides = ppt1.getSlides();
|
||||||
for (HSLFSlide slide : slides) {
|
for (HSLFSlide slide : slides) {
|
||||||
for (HSLFShape sh : slide.getShapes()) {
|
for (HSLFShape sh : slide.getShapes()) {
|
||||||
|
@ -539,37 +516,33 @@ public final class TestTextRun {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HSLFSlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack(ppt1);
|
try (HSLFSlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack(ppt1)) {
|
||||||
for(HSLFSlide slide : ppt2.getSlides()){
|
List<HSLFTextRun> runs = ppt2.getSlides().stream()
|
||||||
for(HSLFShape sh : slide.getShapes()){
|
.flatMap(s -> s.getShapes().stream())
|
||||||
if(sh instanceof HSLFTextShape){
|
.filter(s -> s instanceof HSLFTextShape)
|
||||||
HSLFTextShape tx = (HSLFTextShape)sh;
|
.map(s -> ((HSLFTextShape) s).getTextParagraphs().get(0).getTextRuns().get(0))
|
||||||
List<HSLFTextParagraph> run = tx.getTextParagraphs();
|
.collect(Collectors.toList());
|
||||||
HSLFTextRun rt = run.get(0).getTextRuns().get(0);
|
|
||||||
assertTrue(rt.isBold());
|
assertFalse(runs.isEmpty());
|
||||||
assertEquals(Color.RED, getColor(rt.getFontColor()));
|
assertTrue(runs.stream().allMatch(HSLFTextRun::isBold));
|
||||||
|
assertTrue(runs.stream().map(HSLFTextRun::getFontColor)
|
||||||
|
.map(BaseTestSlideShow::getColor).allMatch(Color.RED::equals));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ppt2.close();
|
|
||||||
ppt1.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test52244() throws IOException {
|
void test52244() throws IOException {
|
||||||
HSLFSlideShow ppt = HSLFTestDataSamples.getSlideShow("52244.ppt");
|
try (HSLFSlideShow ppt = getSlideShow("52244.ppt")) {
|
||||||
HSLFSlide slide = ppt.getSlides().get(0);
|
HSLFSlide slide = ppt.getSlides().get(0);
|
||||||
|
|
||||||
int[] sizes = {36, 24, 12, 32, 12, 12};
|
List<HSLFTextRun> runs = slide.getTextParagraphs().stream().map(tp -> tp.get(0).getTextRuns().get(0)).collect(Collectors.toList());
|
||||||
|
assertTrue(runs.stream().map(HSLFTextRun::getFontFamily).allMatch("Arial"::equals));
|
||||||
|
|
||||||
int i=0;
|
int[] exp = {36, 24, 12, 32, 12, 12};
|
||||||
for (List<HSLFTextParagraph> textParas : slide.getTextParagraphs()) {
|
int[] act = runs.stream().map(HSLFTextRun::getFontSize).mapToInt(Double::intValue).toArray();
|
||||||
HSLFTextRun first = textParas.get(0).getTextRuns().get(0);
|
assertArrayEquals(exp, act);
|
||||||
assertEquals("Arial", first.getFontFamily());
|
|
||||||
assertNotNull(first.getFontSize());
|
|
||||||
assertEquals(sizes[i++], first.getFontSize().intValue());
|
|
||||||
}
|
}
|
||||||
ppt.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -583,4 +556,66 @@ public final class TestTextRun {
|
||||||
assertEquals("\npara", title.getText());
|
assertEquals("\npara", title.getText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void datetimeFormats() throws IOException {
|
||||||
|
LocalDateTime ldt = LocalDateTime.of(2012, 3, 4, 23, 45, 26);
|
||||||
|
final Map<Locale, String[]> formats = new HashMap<>();
|
||||||
|
formats.put(Locale.GERMANY, new String[]{
|
||||||
|
"04.03.2012",
|
||||||
|
"Sonntag, 4. M\u00e4rz 2012",
|
||||||
|
"04/03/12",
|
||||||
|
"4. M\u00e4rz 2012",
|
||||||
|
"12-03-04",
|
||||||
|
"M\u00e4rz 12",
|
||||||
|
"M\u00e4r-12",
|
||||||
|
"04.03.12 23:45",
|
||||||
|
"04.03.12 23:45:26",
|
||||||
|
"23:45",
|
||||||
|
"23:45:26",
|
||||||
|
"11:45",
|
||||||
|
"11:45:26"
|
||||||
|
});
|
||||||
|
formats.put(Locale.US, new String[]{
|
||||||
|
"03/04/2012",
|
||||||
|
"Sunday, March 4, 2012",
|
||||||
|
"4 March 2012",
|
||||||
|
"March 04, 2012",
|
||||||
|
"4-Mar-12",
|
||||||
|
"March 12",
|
||||||
|
"Mar-12",
|
||||||
|
"3/4/12 11:45 PM",
|
||||||
|
"3/4/12 11:45:26 PM",
|
||||||
|
"23:45",
|
||||||
|
"23:45:26",
|
||||||
|
"11:45 PM",
|
||||||
|
"11:45:26 PM"
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
try (HSLFSlideShow ppt = getSlideShow("datetime.ppt")) {
|
||||||
|
List<HSLFTextShape> shapes = ppt.getSlides().get(0).getShapes()
|
||||||
|
.stream().map(HSLFTextShape.class::cast).collect(Collectors.toList());
|
||||||
|
|
||||||
|
int[] expFormatId = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
|
||||||
|
int[] actFormatId = shapes.stream().flatMap(tp -> Stream.of(tp.getTextParagraphs().get(0).getRecords()))
|
||||||
|
.filter(r -> r instanceof DateTimeMCAtom)
|
||||||
|
.mapToInt(r -> ((DateTimeMCAtom)r).getIndex()).toArray();
|
||||||
|
assertArrayEquals(expFormatId, actFormatId);
|
||||||
|
|
||||||
|
List<HSLFShapePlaceholderDetails> phs = shapes.stream().map(HSLFSimpleShape::getPlaceholderDetails).collect(Collectors.toList());
|
||||||
|
|
||||||
|
for (Map.Entry<Locale,String[]> me : formats.entrySet()) {
|
||||||
|
LocaleUtil.setUserLocale(me.getKey());
|
||||||
|
|
||||||
|
// refresh internal members
|
||||||
|
phs.forEach(PlaceholderDetails::getPlaceholder);
|
||||||
|
|
||||||
|
String[] actDate = phs.stream().map(PlaceholderDetails::getDateFormat).map(ldt::format).toArray(String[]::new);
|
||||||
|
assertArrayEquals(me.getValue(), actDate);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
LocaleUtil.resetUserLocale();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ public class DrawMasterSheet extends DrawSheet {
|
||||||
// in XSLF, slidenumber and date shapes aren't marked as placeholders opposed to HSLF
|
// in XSLF, slidenumber and date shapes aren't marked as placeholders opposed to HSLF
|
||||||
Placeholder ph = ((SimpleShape<?,?>)shape).getPlaceholder();
|
Placeholder ph = ((SimpleShape<?,?>)shape).getPlaceholder();
|
||||||
if (ph != null) {
|
if (ph != null) {
|
||||||
return slide.getDisplayPlaceholder(ph);
|
return slide.getDisplayPlaceholder((SimpleShape<?, ?>)shape);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return slide.getFollowMasterGraphics();
|
return slide.getFollowMasterGraphics();
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.apache.poi.sl.draw;
|
package org.apache.poi.sl.draw;
|
||||||
|
|
||||||
|
import static org.apache.logging.log4j.util.Unbox.box;
|
||||||
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
@ -30,8 +32,10 @@ import java.io.InvalidObjectException;
|
||||||
import java.text.AttributedCharacterIterator;
|
import java.text.AttributedCharacterIterator;
|
||||||
import java.text.AttributedCharacterIterator.Attribute;
|
import java.text.AttributedCharacterIterator.Attribute;
|
||||||
import java.text.AttributedString;
|
import java.text.AttributedString;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -47,8 +51,8 @@ import org.apache.poi.sl.usermodel.Hyperlink;
|
||||||
import org.apache.poi.sl.usermodel.Insets2D;
|
import org.apache.poi.sl.usermodel.Insets2D;
|
||||||
import org.apache.poi.sl.usermodel.PaintStyle;
|
import org.apache.poi.sl.usermodel.PaintStyle;
|
||||||
import org.apache.poi.sl.usermodel.PlaceableShape;
|
import org.apache.poi.sl.usermodel.PlaceableShape;
|
||||||
import org.apache.poi.sl.usermodel.ShapeContainer;
|
import org.apache.poi.sl.usermodel.PlaceholderDetails;
|
||||||
import org.apache.poi.sl.usermodel.Sheet;
|
import org.apache.poi.sl.usermodel.SimpleShape;
|
||||||
import org.apache.poi.sl.usermodel.Slide;
|
import org.apache.poi.sl.usermodel.Slide;
|
||||||
import org.apache.poi.sl.usermodel.TextParagraph;
|
import org.apache.poi.sl.usermodel.TextParagraph;
|
||||||
import org.apache.poi.sl.usermodel.TextParagraph.BulletStyle;
|
import org.apache.poi.sl.usermodel.TextParagraph.BulletStyle;
|
||||||
|
@ -61,8 +65,6 @@ import org.apache.poi.util.Internal;
|
||||||
import org.apache.poi.util.LocaleUtil;
|
import org.apache.poi.util.LocaleUtil;
|
||||||
import org.apache.poi.util.Units;
|
import org.apache.poi.util.Units;
|
||||||
|
|
||||||
import static org.apache.logging.log4j.util.Unbox.box;
|
|
||||||
|
|
||||||
public class DrawTextParagraph implements Drawable {
|
public class DrawTextParagraph implements Drawable {
|
||||||
private static final Logger LOG = LogManager.getLogger(DrawTextParagraph.class);
|
private static final Logger LOG = LogManager.getLogger(DrawTextParagraph.class);
|
||||||
|
|
||||||
|
@ -397,11 +399,31 @@ public class DrawTextParagraph implements Drawable {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getRenderableText(Graphics2D graphics, TextRun tr) {
|
protected String getRenderableText(Graphics2D graphics, TextRun tr) {
|
||||||
if (tr.getFieldType() == FieldType.SLIDE_NUMBER) {
|
FieldType ft = tr.getFieldType();
|
||||||
|
if (ft == null) {
|
||||||
|
return getRenderableText(tr);
|
||||||
|
}
|
||||||
|
if (!tr.getRawText().isEmpty()) {
|
||||||
|
switch (ft) {
|
||||||
|
case SLIDE_NUMBER: {
|
||||||
Slide<?, ?> slide = (Slide<?, ?>) graphics.getRenderingHint(Drawable.CURRENT_SLIDE);
|
Slide<?, ?> slide = (Slide<?, ?>) graphics.getRenderingHint(Drawable.CURRENT_SLIDE);
|
||||||
return (slide == null) ? "" : Integer.toString(slide.getSlideNumber());
|
return (slide == null) ? "" : Integer.toString(slide.getSlideNumber());
|
||||||
}
|
}
|
||||||
return getRenderableText(tr);
|
case DATE_TIME: {
|
||||||
|
PlaceholderDetails pd = ((SimpleShape<?, ?>) this.getParagraphShape()).getPlaceholderDetails();
|
||||||
|
// refresh internal members
|
||||||
|
pd.getPlaceholder();
|
||||||
|
String uda = pd.getUserDate();
|
||||||
|
if (uda != null) {
|
||||||
|
return uda;
|
||||||
|
}
|
||||||
|
Calendar cal = LocaleUtil.getLocaleCalendar();
|
||||||
|
LocalDateTime now = LocalDateTime.ofInstant(cal.toInstant(), cal.getTimeZone().toZoneId());
|
||||||
|
return now.format(pd.getDateFormat());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Internal
|
@Internal
|
||||||
|
@ -550,30 +572,8 @@ public class DrawTextParagraph implements Drawable {
|
||||||
/**
|
/**
|
||||||
* Helper method for paint style relative to bounds, e.g. gradient paint
|
* Helper method for paint style relative to bounds, e.g. gradient paint
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
private PlaceableShape<?,?> getParagraphShape() {
|
private PlaceableShape<?,?> getParagraphShape() {
|
||||||
return new PlaceableShape(){
|
return paragraph.getParentShape();
|
||||||
@Override
|
|
||||||
public ShapeContainer<?,?> getParent() { return null; }
|
|
||||||
@Override
|
|
||||||
public Rectangle2D getAnchor() { return paragraph.getParentShape().getAnchor(); }
|
|
||||||
@Override
|
|
||||||
public void setAnchor(Rectangle2D anchor) {}
|
|
||||||
@Override
|
|
||||||
public double getRotation() { return 0; }
|
|
||||||
@Override
|
|
||||||
public void setRotation(double theta) {}
|
|
||||||
@Override
|
|
||||||
public void setFlipHorizontal(boolean flip) {}
|
|
||||||
@Override
|
|
||||||
public void setFlipVertical(boolean flip) {}
|
|
||||||
@Override
|
|
||||||
public boolean getFlipHorizontal() { return false; }
|
|
||||||
@Override
|
|
||||||
public boolean getFlipVertical() { return false; }
|
|
||||||
@Override
|
|
||||||
public Sheet<?,?> getSheet() { return paragraph.getParentShape().getSheet(); }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<AttributedStringData> getAttributedString(Graphics2D graphics, StringBuilder text) {
|
protected List<AttributedStringData> getAttributedString(Graphics2D graphics, StringBuilder text) {
|
||||||
|
@ -671,9 +671,11 @@ public class DrawTextParagraph implements Drawable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processing the glyphs is done in two steps.
|
* Processing the glyphs is done in two steps:
|
||||||
* <li>determine the font group - a text run can have different font groups. Depending on the chars,
|
* <ul>
|
||||||
* the correct font group needs to be used
|
* <li>1. determine the font group - a text run can have different font groups.
|
||||||
|
* <li>2. Depending on the chars, the correct font group needs to be used
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* @see <a href="https://blogs.msdn.microsoft.com/officeinteroperability/2013/04/22/office-open-xml-themes-schemes-and-fonts/">Office Open XML Themes, Schemes, and Fonts</a>
|
* @see <a href="https://blogs.msdn.microsoft.com/officeinteroperability/2013/04/22/office-open-xml-themes-schemes-and-fonts/">Office Open XML Themes, Schemes, and Fonts</a>
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
package org.apache.poi.sl.usermodel;
|
package org.apache.poi.sl.usermodel;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extended details about placholders
|
* Extended details about placholders
|
||||||
*
|
*
|
||||||
|
@ -66,4 +68,23 @@ public interface PlaceholderDetails {
|
||||||
* @since POI 4.0.0
|
* @since POI 4.0.0
|
||||||
*/
|
*/
|
||||||
void setText(String text);
|
void setText(String text);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the stored / fixed user specified date
|
||||||
|
*
|
||||||
|
* @since POI 5.2.0
|
||||||
|
*/
|
||||||
|
default String getUserDate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Get the date format for the datetime placeholder
|
||||||
|
*
|
||||||
|
* @since POI 5.2.0
|
||||||
|
*/
|
||||||
|
default DateTimeFormatter getDateFormat() {
|
||||||
|
return DateTimeFormatter.ISO_LOCAL_DATE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ package org.apache.poi.sl.usermodel;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.poi.util.Removal;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public interface Slide<
|
public interface Slide<
|
||||||
S extends Shape<S,P>,
|
S extends Shape<S,P>,
|
||||||
|
@ -54,8 +56,29 @@ public interface Slide<
|
||||||
* @param placeholder the placeholder type
|
* @param placeholder the placeholder type
|
||||||
* @return {@code true} if the placeholder should be displayed/rendered
|
* @return {@code true} if the placeholder should be displayed/rendered
|
||||||
* @since POI 3.16-beta2
|
* @since POI 3.16-beta2
|
||||||
|
*
|
||||||
|
* @deprecated in POI 5.2.0 - use {@link #getDisplayPlaceholder(SimpleShape)}
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
boolean getDisplayPlaceholder(Placeholder placeholder);
|
@Deprecated
|
||||||
|
@Removal(version = "6.0.0")
|
||||||
|
default boolean getDisplayPlaceholder(Placeholder placeholder) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In XSLF, slidenumber and date shapes aren't marked as placeholders
|
||||||
|
* whereas in HSLF they are activated via a HeadersFooter configuration.
|
||||||
|
* This method is used to generalize that handling.
|
||||||
|
*
|
||||||
|
* @param placeholderRefShape the shape which references to the placeholder
|
||||||
|
* @return {@code true} if the placeholder should be displayed/rendered
|
||||||
|
* @since POI 5.2.0
|
||||||
|
*/
|
||||||
|
default boolean getDisplayPlaceholder(SimpleShape<?,?> placeholderRefShape) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the slide visibility
|
* Sets the slide visibility
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue