blob: 9424a37dd64a1c75d15f88e1a2a12867f956bea2 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed 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 com.intellij.openapi.editor.richcopy.view;
import com.intellij.openapi.editor.richcopy.model.ColorRegistry;
import com.intellij.openapi.editor.richcopy.model.FontNameRegistry;
import com.intellij.openapi.editor.richcopy.model.MarkupHandler;
import com.intellij.openapi.editor.richcopy.model.SyntaxInfo;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
public class RtfTransferableData extends AbstractSyntaxAwareInputStreamTransferableData {
@NotNull public static final DataFlavor FLAVOR = new DataFlavor("text/rtf;class=java.io.InputStream", "RTF text");
@NotNull private static final String HEADER_PREFIX = "{\\rtf1\\ansi\\deff0";
@NotNull private static final String HEADER_SUFFIX = "}";
@NotNull private static final String TAB = "\\tab\n";
@NotNull private static final String NEW_LINE = "\\line\n";
@NotNull private static final String BOLD = "\\b";
@NotNull private static final String ITALIC = "\\i";
public RtfTransferableData(@NotNull SyntaxInfo syntaxInfo) {
super(syntaxInfo, FLAVOR);
}
@Override
protected void build(@NotNull final StringBuilder holder, final int maxLength) {
holder.append(HEADER_PREFIX);
holder.append("{\\colortbl;");
ColorRegistry colorRegistry = mySyntaxInfo.getColorRegistry();
for (int id : colorRegistry.getAllIds()) {
Color color = colorRegistry.dataById(id);
holder.append(String.format("\\red%d\\green%d\\blue%d;", color.getRed(), color.getGreen(), color.getBlue()));
}
holder.append("}\n");
holder.append("{\\fonttbl");
FontNameRegistry fontNameRegistry = mySyntaxInfo.getFontNameRegistry();
for (int id : fontNameRegistry.getAllIds()) {
String fontName = fontNameRegistry.dataById(id);
holder.append(String.format("{\\f%d %s;}", id, fontName));
}
holder.append("}\n");
holder.append("\n\\s0\\box")
.append("\\cbpat").append(mySyntaxInfo.getDefaultBackground())
.append("\\cb").append(mySyntaxInfo.getDefaultBackground());
addFontSize(holder, mySyntaxInfo.getFontSize());
holder.append('\n');
mySyntaxInfo.processOutputInfo(new MyVisitor(holder, myRawText, mySyntaxInfo, maxLength));
holder.append("\\par");
holder.append(HEADER_SUFFIX);
}
@NotNull
@Override
protected String getCharset() {
return "US-ASCII";
}
private static void addFontSize(StringBuilder buffer, int fontSize) {
buffer.append("\\fs").append(fontSize * 2);
}
private static class MyVisitor implements MarkupHandler {
@NotNull private final StringBuilder myBuffer;
@NotNull private final String myRawText;
private final int myMaxLength;
private final int myDefaultBackgroundId;
private final int myFontSize;
private int myForegroundId = -1;
private int myFontNameId = -1;
private int myFontStyle = -1;
MyVisitor(@NotNull StringBuilder buffer, @NotNull String rawText, @NotNull SyntaxInfo syntaxInfo, int maxLength) {
myBuffer = buffer;
myRawText = rawText;
myMaxLength = maxLength;
myDefaultBackgroundId = syntaxInfo.getDefaultBackground();
myFontSize = syntaxInfo.getFontSize();
}
@Override
public void handleText(int startOffset, int endOffset) throws Exception {
myBuffer.append("\n");
for (int i = startOffset; i < endOffset; i++) {
char c = myRawText.charAt(i);
if (c > 127) {
// Escape non-ascii symbols.
myBuffer.append(String.format("\\u%04d?", (int)c));
continue;
}
switch (c) {
case '\t':
myBuffer.append(TAB);
continue;
case '\n':
myBuffer.append(NEW_LINE);
continue;
case '\\':
case '{':
case '}':
myBuffer.append('\\');
}
myBuffer.append(c);
}
}
@Override
public void handleBackground(int backgroundId) throws Exception {
if (backgroundId == myDefaultBackgroundId) {
myBuffer.append("\\plain"); // we cannot use \chcbpat with default background id, as it doesn't work in MS Word,
// and we cannot use \chcbpat0 as it doesn't work in OpenOffice
addFontSize(myBuffer, myFontSize);
if (myFontNameId >= 0) {
handleFont(myFontNameId);
}
if (myForegroundId >= 0) {
handleForeground(myForegroundId);
}
if (myFontStyle >= 0) {
handleStyle(myFontStyle);
}
}
else {
myBuffer.append("\\chcbpat").append(backgroundId);
}
myBuffer.append("\\cb").append(backgroundId);
myBuffer.append('\n');
}
@Override
public void handleForeground(int foregroundId) throws Exception {
myBuffer.append("\\cf").append(foregroundId).append('\n');
myForegroundId = foregroundId;
}
@Override
public void handleFont(int fontNameId) throws Exception {
myBuffer.append("\\f").append(fontNameId).append('\n');
myFontNameId = fontNameId;
}
@Override
public void handleStyle(int style) throws Exception {
myBuffer.append(ITALIC);
if ((style & Font.ITALIC) == 0) {
myBuffer.append('0');
}
myBuffer.append(BOLD);
if ((style & Font.BOLD) == 0) {
myBuffer.append('0');
}
myBuffer.append('\n');
myFontStyle = style;
}
@Override
public boolean canHandleMore() {
if (myBuffer.length() > myMaxLength) {
myBuffer.append("... truncated ...");
return false;
}
return true;
}
}
}