git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1895248 13f79535-47bb-0310-9956-ffa450edef68tags/REL_5_2_0
* 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 | ||||
*/ | */ | ||||
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(); |
public HeadersFooters(HSLFSheet sheet, short headerFooterType) { | public HeadersFooters(HSLFSheet sheet, short headerFooterType) { | ||||
_sheet = sheet; | _sheet = sheet; | ||||
@SuppressWarnings("resource") | @SuppressWarnings("resource") | ||||
HSLFSlideShow ppt = _sheet.getSlideShow(); | HSLFSlideShow ppt = _sheet.getSlideShow(); | ||||
Document doc = ppt.getDocumentRecord(); | Document doc = ppt.getDocumentRecord(); | ||||
// detect if this ppt was saved in Office2007 | // detect if this ppt was saved in Office2007 | ||||
String tag = ppt.getSlideMasters().get(0).getProgrammableTag(); | String tag = ppt.getSlideMasters().get(0).getProgrammableTag(); | ||||
_ppt2007 = _ppt2007tag.equals(tag); | _ppt2007 = _ppt2007tag.equals(tag); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (hdd == null) { | if (hdd == null) { | ||||
hdd = new HeadersFootersContainer(headerFooterType); | hdd = new HeadersFootersContainer(headerFooterType); | ||||
Record lst = doc.findFirstOfType(RecordTypes.List.typeID); | Record lst = doc.findFirstOfType(RecordTypes.List.typeID); | ||||
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. | ||||
*/ | */ | ||||
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. | ||||
*/ | */ | ||||
public boolean isPpt2007() { | public boolean isPpt2007() { | ||||
return _ppt2007; | return _ppt2007; | ||||
} | } | ||||
public HeadersFootersContainer getContainer() { | |||||
return _container; | |||||
} | |||||
} | } |
/* ==================================================================== | |||||
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 | |||||
); | |||||
} | |||||
} |
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; | ||||
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() | ||||
/** | /** | ||||
* 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); | ||||
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. | ||||
* | * | ||||
@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) | ||||
); | ); | ||||
} | } |
*/ | */ | ||||
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; | ||||
/** | /** | ||||
* 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; | ||||
* 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. | ||||
*/ | */ |
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), |
} | } | ||||
@Override | |||||
public boolean isVisible() { | public boolean isVisible() { | ||||
final Placeholder ph = getPlaceholder(); | final Placeholder ph = getPlaceholder(); | ||||
if (ph == null) { | if (ph == null) { | ||||
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: | ||||
} | } | ||||
} | } | ||||
@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) { |
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 | ||||
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) { | ||||
} | } | ||||
} | } | ||||
@Override | |||||
public Placeholder getPlaceholder() { | public Placeholder getPlaceholder() { | ||||
updatePlaceholderAtom(false); | updatePlaceholderAtom(false); | ||||
final int phId; | final int phId; | ||||
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; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
@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(); | ||||
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) { | ||||
return null; | return null; | ||||
} | } | ||||
final int size = (oePlaceholderAtom != null) | |||||
final int size = (oePlaceholderAtom != null) | |||||
? oePlaceholderAtom.getPlaceholderSize() | ? oePlaceholderAtom.getPlaceholderSize() | ||||
: OEPlaceholderAtom.PLACEHOLDER_HALFSIZE; | : OEPlaceholderAtom.PLACEHOLDER_HALFSIZE; | ||||
switch (size) { | switch (size) { | ||||
case OEPlaceholderAtom.PLACEHOLDER_FULLSIZE: | case OEPlaceholderAtom.PLACEHOLDER_FULLSIZE: | ||||
return PlaceholderSize.full; | return PlaceholderSize.full; | ||||
} | } | ||||
} | } | ||||
@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) { | ||||
return; | return; | ||||
} | } | ||||
updatePlaceholderAtom(true); | updatePlaceholderAtom(true); | ||||
final byte ph_size; | final byte ph_size; | ||||
switch (size) { | switch (size) { | ||||
case full: | case full: | ||||
} | } | ||||
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; | ||||
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); | |||||
} | |||||
} | } |
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; | ||||
* @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. | ||||
(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: | default: | ||||
return false; | 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 | @Override | ||||
public HSLFMasterSheet getSlideLayout(){ | public HSLFMasterSheet getSlideLayout(){ | ||||
// TODO: find out how we can find the mastersheet base on the slide layout type, i.e. | // TODO: find out how we can find the mastersheet base on the slide layout type, i.e. |
/* ==================================================================== | |||||
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); | |||||
} | |||||
} | |||||
} |
// 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(); |
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; | ||||
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; | ||||
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.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.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; | ||||
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); | ||||
} | } | ||||
protected String getRenderableText(Graphics2D graphics, TextRun tr) { | 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 | @Internal | ||||
/** | /** | ||||
* 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(){ | |||||
@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) { | protected List<AttributedStringData> getAttributedString(Graphics2D graphics, StringBuilder text) { | ||||
} | } | ||||
/** | /** | ||||
* 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> | * @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> | ||||
*/ | */ |
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 | ||||
* | * | ||||
enum PlaceholderSize { | enum PlaceholderSize { | ||||
quarter, half, full | quarter, half, full | ||||
} | } | ||||
Placeholder getPlaceholder(); | Placeholder getPlaceholder(); | ||||
/** | /** | ||||
* @param placeholder The shape to use as placeholder or null if no placeholder should be set. | * @param placeholder The shape to use as placeholder or null if no placeholder should be set. | ||||
*/ | */ | ||||
void setPlaceholder(Placeholder placeholder); | void setPlaceholder(Placeholder placeholder); | ||||
boolean isVisible(); | boolean isVisible(); | ||||
void setVisible(boolean isVisible); | void setVisible(boolean isVisible); | ||||
PlaceholderSize getSize(); | PlaceholderSize getSize(); | ||||
void setSize(PlaceholderSize size); | void setSize(PlaceholderSize size); | ||||
/** | /** | ||||
* @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; | |||||
} | |||||
} | } |
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>, | ||||
* @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)} | |||||
* | |||||
*/ | |||||
@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 | * Sets the slide visibility |