git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1895248 13f79535-47bb-0310-9956-ffa450edef68tags/REL_5_2_0
@@ -70,7 +70,7 @@ implements Slide<XSLFShape,XSLFTextParagraph> { | |||
* Construct a SpreadsheetML slide from a package part | |||
* | |||
* @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 | |||
*/ | |||
@@ -377,12 +377,6 @@ implements Slide<XSLFShape,XSLFTextParagraph> { | |||
draw.draw(graphics); | |||
} | |||
@Override | |||
public boolean getDisplayPlaceholder(Placeholder placeholder) { | |||
return false; | |||
} | |||
@Override | |||
public void setHidden(boolean hidden) { | |||
CTSlide sld = getXmlObject(); |
@@ -50,11 +50,11 @@ public final class HeadersFooters { | |||
public HeadersFooters(HSLFSheet sheet, short headerFooterType) { | |||
_sheet = sheet; | |||
@SuppressWarnings("resource") | |||
HSLFSlideShow ppt = _sheet.getSlideShow(); | |||
Document doc = ppt.getDocumentRecord(); | |||
// detect if this ppt was saved in Office2007 | |||
String tag = ppt.getSlideMasters().get(0).getProgrammableTag(); | |||
_ppt2007 = _ppt2007tag.equals(tag); | |||
@@ -72,7 +72,7 @@ public final class HeadersFooters { | |||
} | |||
} | |||
} | |||
if (hdd == null) { | |||
hdd = new HeadersFootersContainer(headerFooterType); | |||
Record lst = doc.findFirstOfType(RecordTypes.List.typeID); | |||
@@ -206,6 +206,18 @@ public final class HeadersFooters { | |||
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. | |||
*/ | |||
@@ -213,6 +225,20 @@ public final class HeadersFooters { | |||
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. | |||
*/ | |||
@@ -282,4 +308,8 @@ public final class HeadersFooters { | |||
public boolean isPpt2007() { | |||
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; | |||
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString; | |||
import static org.apache.poi.util.GenericRecordUtil.safeEnum; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
@@ -37,30 +36,6 @@ import org.apache.poi.util.LittleEndian; | |||
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. | |||
* @see #getMask() | |||
@@ -136,7 +111,7 @@ public final class HeadersFootersAtom extends RecordAtom { | |||
/** | |||
* 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 | |||
_header = Arrays.copyOfRange(source, start, start+8); | |||
@@ -182,6 +157,7 @@ public final class HeadersFootersAtom extends RecordAtom { | |||
return LittleEndian.getShort(_recdata, 0); | |||
} | |||
/** | |||
* 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 | |||
public Map<String, Supplier<?>> getGenericProperties() { | |||
return GenericRecordUtil.getGenericProperties( | |||
"formatIndex", safeEnum(FormatIndex.values(), this::getFormatId), | |||
"formatIndex", this::getFormatId, | |||
"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; | |||
private byte[] _header; | |||
private final byte[] _header; | |||
private int placementId; | |||
private int placeholderId; | |||
@@ -77,7 +77,7 @@ public final class OEPlaceholderAtom extends RecordAtom{ | |||
/** | |||
* 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); | |||
int offset = start+8; | |||
@@ -135,7 +135,7 @@ public final class OEPlaceholderAtom extends RecordAtom{ | |||
* Sets the placeholder Id.<p> | |||
* | |||
* 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. | |||
*/ |
@@ -134,7 +134,7 @@ public enum RecordTypes { | |||
InteractiveInfoAtom(4083,InteractiveInfoAtom::new), | |||
UserEditAtom(4085,UserEditAtom::new), | |||
CurrentUserAtom(4086,null), | |||
DateTimeMCAtom(4087,null), | |||
DateTimeMCAtom(4087,DateTimeMCAtom::new), | |||
GenericDateMCAtom(4088,null), | |||
FooterMCAtom(4090,null), | |||
ExControlAtom(4091,ExControlAtom::new), |
@@ -36,6 +36,7 @@ public class HSLFPlaceholderDetails implements PlaceholderDetails { | |||
} | |||
@Override | |||
public boolean isVisible() { | |||
final Placeholder ph = getPlaceholder(); | |||
if (ph == null) { | |||
@@ -46,13 +47,12 @@ public class HSLFPlaceholderDetails implements PlaceholderDetails { | |||
switch (ph) { | |||
case HEADER: | |||
case TITLE: | |||
return headersFooters.isHeaderVisible(); | |||
case FOOTER: | |||
return headersFooters.isFooterVisible(); | |||
case DATETIME: | |||
return headersFooters.isDateTimeVisible(); | |||
case TITLE: | |||
return headersFooters.isHeaderVisible(); | |||
case SLIDE_NUMBER: | |||
return headersFooters.isSlideNumberVisible(); | |||
default: | |||
@@ -60,6 +60,7 @@ public class HSLFPlaceholderDetails implements PlaceholderDetails { | |||
} | |||
} | |||
@Override | |||
public void setVisible(final boolean isVisible) { | |||
final Placeholder ph = getPlaceholder(); | |||
if (ph == null) { |
@@ -17,15 +17,29 @@ | |||
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.EscherSpRecord; | |||
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.HeadersFootersAtom; | |||
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.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.Placeholder; | |||
import org.apache.poi.util.LocaleID; | |||
import org.apache.poi.util.LocaleUtil; | |||
/** | |||
* Extended placeholder details for HSLF shapes | |||
@@ -41,6 +55,7 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails { | |||
final HSLFSimpleShape shape; | |||
private OEPlaceholderAtom oePlaceholderAtom; | |||
private RoundTripHFPlaceholder12 roundTripHFPlaceholder12; | |||
private DateTimeMCAtom localDateTime; | |||
HSLFShapePlaceholderDetails(final HSLFSimpleShape shape) { | |||
@@ -61,6 +76,7 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails { | |||
} | |||
} | |||
@Override | |||
public Placeholder getPlaceholder() { | |||
updatePlaceholderAtom(false); | |||
final int phId; | |||
@@ -68,6 +84,8 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails { | |||
phId = oePlaceholderAtom.getPlaceholderId(); | |||
} else if (roundTripHFPlaceholder12 != null) { | |||
phId = roundTripHFPlaceholder12.getPlaceholderId(); | |||
} else if (localDateTime != null) { | |||
return Placeholder.DATETIME; | |||
} else { | |||
return null; | |||
} | |||
@@ -85,6 +103,7 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails { | |||
} | |||
} | |||
@Override | |||
public void setPlaceholder(final Placeholder placeholder) { | |||
final EscherSpRecord spRecord = shape.getEscherChild(EscherSpRecord.RECORD_ID); | |||
int flags = spRecord.getFlags(); | |||
@@ -111,16 +130,17 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails { | |||
roundTripHFPlaceholder12.setPlaceholderId(phId); | |||
} | |||
@Override | |||
public PlaceholderSize getSize() { | |||
final Placeholder ph = getPlaceholder(); | |||
if (ph == null) { | |||
return null; | |||
} | |||
final int size = (oePlaceholderAtom != null) | |||
final int size = (oePlaceholderAtom != null) | |||
? oePlaceholderAtom.getPlaceholderSize() | |||
: OEPlaceholderAtom.PLACEHOLDER_HALFSIZE; | |||
switch (size) { | |||
case OEPlaceholderAtom.PLACEHOLDER_FULLSIZE: | |||
return PlaceholderSize.full; | |||
@@ -132,13 +152,14 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails { | |||
} | |||
} | |||
@Override | |||
public void setSize(final PlaceholderSize size) { | |||
final Placeholder ph = getPlaceholder(); | |||
if (ph == null || size == null) { | |||
return; | |||
} | |||
updatePlaceholderAtom(true); | |||
final byte ph_size; | |||
switch (size) { | |||
case full: | |||
@@ -202,6 +223,14 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails { | |||
} | |||
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); | |||
if (clientData == null) { | |||
oePlaceholderAtom = null; | |||
@@ -237,4 +266,38 @@ public class HSLFShapePlaceholderDetails extends HSLFPlaceholderDetails { | |||
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.Placeholder; | |||
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.TextShape.TextPlaceholder; | |||
@@ -259,7 +260,7 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFTe | |||
* @return set of records inside {@code SlideListWithtext} container | |||
* 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. | |||
@@ -495,18 +496,41 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFTe | |||
(slt == SlideLayoutType.TITLE_SLIDE || slt == SlideLayoutType.TITLE_ONLY || slt == SlideLayoutType.MASTER_TITLE); | |||
switch (placeholder) { | |||
case DATETIME: | |||
return hf.isDateTimeVisible() && !isTitle; | |||
return (hf.isDateTimeVisible() && (hf.isTodayDateVisible() || (hf.isUserDateVisible() && hf.getUserDateAtom() != null))) && !isTitle; | |||
case SLIDE_NUMBER: | |||
return hf.isSlideNumberVisible() && !isTitle; | |||
case HEADER: | |||
return hf.isHeaderVisible() && !isTitle; | |||
return hf.isHeaderVisible() && hf.getHeaderAtom() != null && !isTitle; | |||
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: | |||
return false; | |||
} | |||
} | |||
@Override | |||
public HSLFMasterSheet getSlideLayout(){ | |||
// TODO: find out how we can find the mastersheet base on the slide layout type, i.e. |
@@ -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); | |||
} | |||
} | |||
} |
@@ -45,7 +45,7 @@ public class DrawMasterSheet extends DrawSheet { | |||
// in XSLF, slidenumber and date shapes aren't marked as placeholders opposed to HSLF | |||
Placeholder ph = ((SimpleShape<?,?>)shape).getPlaceholder(); | |||
if (ph != null) { | |||
return slide.getDisplayPlaceholder(ph); | |||
return slide.getDisplayPlaceholder((SimpleShape<?, ?>)shape); | |||
} | |||
} | |||
return slide.getFollowMasterGraphics(); |
@@ -17,6 +17,8 @@ | |||
package org.apache.poi.sl.draw; | |||
import static org.apache.logging.log4j.util.Unbox.box; | |||
import java.awt.Dimension; | |||
import java.awt.Font; | |||
import java.awt.Graphics2D; | |||
@@ -30,8 +32,10 @@ import java.io.InvalidObjectException; | |||
import java.text.AttributedCharacterIterator; | |||
import java.text.AttributedCharacterIterator.Attribute; | |||
import java.text.AttributedString; | |||
import java.time.LocalDateTime; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.Calendar; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
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.PaintStyle; | |||
import org.apache.poi.sl.usermodel.PlaceableShape; | |||
import org.apache.poi.sl.usermodel.ShapeContainer; | |||
import org.apache.poi.sl.usermodel.Sheet; | |||
import org.apache.poi.sl.usermodel.PlaceholderDetails; | |||
import org.apache.poi.sl.usermodel.SimpleShape; | |||
import org.apache.poi.sl.usermodel.Slide; | |||
import org.apache.poi.sl.usermodel.TextParagraph; | |||
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.Units; | |||
import static org.apache.logging.log4j.util.Unbox.box; | |||
public class DrawTextParagraph implements Drawable { | |||
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) { | |||
if (tr.getFieldType() == FieldType.SLIDE_NUMBER) { | |||
Slide<?,?> slide = (Slide<?,?>)graphics.getRenderingHint(Drawable.CURRENT_SLIDE); | |||
return (slide == null) ? "" : Integer.toString(slide.getSlideNumber()); | |||
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); | |||
return (slide == null) ? "" : Integer.toString(slide.getSlideNumber()); | |||
} | |||
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 getRenderableText(tr); | |||
return ""; | |||
} | |||
@Internal | |||
@@ -550,30 +572,8 @@ public class DrawTextParagraph implements Drawable { | |||
/** | |||
* Helper method for paint style relative to bounds, e.g. gradient paint | |||
*/ | |||
@SuppressWarnings("rawtypes") | |||
private PlaceableShape<?,?> getParagraphShape() { | |||
return new PlaceableShape(){ | |||
@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(); } | |||
}; | |||
return paragraph.getParentShape(); | |||
} | |||
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. | |||
* <li>determine the font group - a text run can have different font groups. Depending on the chars, | |||
* the correct font group needs to be used | |||
* Processing the glyphs is done in two steps: | |||
* <ul> | |||
* <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> | |||
*/ |
@@ -18,6 +18,8 @@ | |||
package org.apache.poi.sl.usermodel; | |||
import java.time.format.DateTimeFormatter; | |||
/** | |||
* Extended details about placholders | |||
* | |||
@@ -27,7 +29,7 @@ public interface PlaceholderDetails { | |||
enum PlaceholderSize { | |||
quarter, half, full | |||
} | |||
Placeholder getPlaceholder(); | |||
/** | |||
@@ -40,13 +42,13 @@ public interface PlaceholderDetails { | |||
* @param placeholder The shape to use as placeholder or null if no placeholder should be set. | |||
*/ | |||
void setPlaceholder(Placeholder placeholder); | |||
boolean isVisible(); | |||
void setVisible(boolean isVisible); | |||
PlaceholderSize getSize(); | |||
void setSize(PlaceholderSize size); | |||
/** | |||
@@ -66,4 +68,23 @@ public interface PlaceholderDetails { | |||
* @since POI 4.0.0 | |||
*/ | |||
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 org.apache.poi.util.Removal; | |||
@SuppressWarnings("unused") | |||
public interface Slide< | |||
S extends Shape<S,P>, | |||
@@ -54,8 +56,29 @@ public interface Slide< | |||
* @param placeholder the placeholder type | |||
* @return {@code true} if the placeholder should be displayed/rendered | |||
* @since POI 3.16-beta2 | |||
* | |||
* @deprecated in POI 5.2.0 - use {@link #getDisplayPlaceholder(SimpleShape)} | |||
* | |||
*/ | |||
@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 | |||
*/ | |||
boolean getDisplayPlaceholder(Placeholder placeholder); | |||
default boolean getDisplayPlaceholder(SimpleShape<?,?> placeholderRefShape) { | |||
return false; | |||
} | |||
/** | |||
* Sets the slide visibility |