/*
* Copyright 2000-2006 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 jetbrains.communicator.idea;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.openapi.wm.impl.IdeFrameImpl;
import com.intellij.ui.PopupHandler;
import com.intellij.ui.TreeSpeedSearch;
import com.intellij.util.ArrayUtil;
import com.intellij.util.diff.Diff;
import com.intellij.util.ui.tree.TreeUtil;
import com.intellij.xml.util.XmlStringUtil;
import jetbrains.communicator.commands.FindUsersCommand;
import jetbrains.communicator.commands.SendMessageInvoker;
import jetbrains.communicator.core.EventVisitor;
import jetbrains.communicator.core.dispatcher.LocalMessage;
import jetbrains.communicator.core.transport.CodePointerEvent;
import jetbrains.communicator.core.transport.MessageEvent;
import jetbrains.communicator.core.transport.StacktraceEvent;
import jetbrains.communicator.core.transport.TransportEvent;
import jetbrains.communicator.core.users.User;
import jetbrains.communicator.core.vfs.ProjectsData;
import jetbrains.communicator.core.vfs.VFile;
import jetbrains.communicator.ide.*;
import jetbrains.communicator.idea.codePointer.IncomingCodePointerMessage;
import jetbrains.communicator.idea.findUsers.FindUsersDialog;
import jetbrains.communicator.idea.history.ShowHistoryDialog;
import jetbrains.communicator.idea.sendMessage.IncomingLocalMessage;
import jetbrains.communicator.idea.sendMessage.IncomingStacktraceMessage;
import jetbrains.communicator.idea.viewFiles.ViewFilesDialog;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Future;
/**
* @author Kir Maximov
*/
public class IDEAFacade implements IDEFacade {
private static final Logger LOG = Logger.getLogger(IDEAFacade.class);
private ViewFilesDialog myViewFilesDialog;
@Override
public void showMessage(String title, String message) {
Messages.showMessageDialog(message, title, Messages.getInformationIcon());
}
@Override
public boolean askQuestion(String title, String question) {
//noinspection HardCodedStringLiteral
int result = JOptionPane.showOptionDialog(null,
new JLabel(XmlStringUtil.wrapInHtml(question.replaceAll("\n","<br>"))), title,
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
null, null, null);
return result == JOptionPane.YES_OPTION;
}
@Override
public File getCacheDir() {
//noinspection HardCodedStringLiteral
File file = new File(PathManager.getSystemPath(), "ideTalk");
file.mkdir();
return file;
}
@Override
public File getConfigDir() {
@NonNls File file = new File(PathManager.getConfigPath(), "ideTalk");
file.mkdir();
return file;
}
@Override
public FindUsersCommand.UsersInfo chooseUsersToBeAdded(List<User> foundNewUsers, String[] groups) {
FindUsersDialog dialog = new FindUsersDialog(foundNewUsers, groups);
if (dialog.showAndGet()) {
Set<User> selectedUsers = dialog.getSelectedUsers();
return new FindUsersCommand.UsersInfo(selectedUsers.toArray(new User[selectedUsers.size()]), dialog.getGroup());
}
return new FindUsersCommand.UsersInfo();
}
@Override
public String getMessageLine(String labelText, String titleText) {
return Messages.showInputDialog(labelText, titleText, Messages.getQuestionIcon());
}
@Override
public String getMessage(String labelText, String titleText, String optionalOKButtonText) {
GetMessageDialog dialog = new GetMessageDialog(titleText, labelText, optionalOKButtonText);
dialog.show();
return dialog.getEnteredText();
}
@Override
public Future<?> runOnPooledThread(Runnable toRun) {
return ApplicationManager.getApplication().executeOnPooledThread(toRun);
}
@Override
public void runLongProcess(String processTitle, final Process process) throws CanceledException {
try {
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
@Override
public void run() {
final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
if (progressIndicator == null) {
process.run(new NullProgressIndicator(){
@Override
public void checkCanceled() {
super.checkCanceled();
throw new ProcessCanceledException();
}
});
}
else {
progressIndicator.pushState();
try {
process.run(new jetbrains.communicator.ide.ProgressIndicator() {
@Override
public void setIndefinite(boolean indefinite) {
progressIndicator.setIndeterminate(indefinite);
}
@Override
public void setText(String text) {
progressIndicator.setText(text);
}
@Override
public void setFraction(double x) {
progressIndicator.setFraction(x);
}
@Override
public void checkCanceled() {
progressIndicator.checkCanceled();
}
});
}
finally {
progressIndicator.popState();
}
}
}
}, processTitle, true, null);
} catch (ProcessCanceledException e) {
throw new CanceledException(e);
}
}
@Override
public void invokeSendMessage(User[] allUsers, User[] defaultTargetUsers, String message, SendMessageInvoker sendMessageInvoker) {
Project project = getProject(null);
assert project != null: "Null project when sending message";
IDEtalkMessagesWindow messagesWindow = project.getComponent(IDEtalkMessagesWindow.class);
if (messagesWindow != null && project.isInitialized()) {
messagesWindow.expandToolWindow();
for (User user : defaultTargetUsers) {
messagesWindow.showUserTabAndRequestFocus(user);
messagesWindow.appendInputText(user, message);
}
}
}
@Override
public void showSearchHistoryResults(List<LocalMessage> foundMessages, User user) {
Project project = getProject(null);
assert project != null;
new ShowHistoryDialog(project, foundMessages, user).show();
}
@Override
public ProjectsData getProjectsData() {
final ProjectsData result = new ProjectsData();
ApplicationManager.getApplication().runReadAction(() -> {
try {
new ProjectsDataFiller(result).fillProjectsData();
} catch (Throwable e) {
LOG.info(e, e);
}
});
return result;
}
@Override
public String[] getProjects() {
Project[] projects = ProjectManager.getInstance().getOpenProjects();
List<String> result = new ArrayList<>();
for (Project project : projects) {
result.add(project.getName());
}
return ArrayUtil.toStringArray(result);
}
@Override
public void showUserFiles(User user, ProjectsData data) {
if (myViewFilesDialog == null) {
myViewFilesDialog = new ViewFilesDialog(user, data, this) {
@Override
protected void dispose() {
super.dispose();
myViewFilesDialog = null;
}
};
myViewFilesDialog.show();
}
else {
myViewFilesDialog.refreshData(user, data);
}
}
@Override
public boolean hasFile(VFile file) {
VirtualFile virtualFile = VFSUtil.getVirtualFile(file);
return virtualFile != null && virtualFile.isValid();
}
@Override
public void open(VFile file) {
VirtualFile virtualFile = VFSUtil.getVirtualFile(file);
Project project = getProject(null);
assert project != null;
if (virtualFile != null) {
FileEditorManager.getInstance(project).openFile(virtualFile, false);
}
}
@Override
public void fillFileContents(final VFile vFile) {
vFile.setContents(null);
final VirtualFile virtualFile = VFSUtil.getVirtualFile(vFile);
if (virtualFile == null) return;
ApplicationManager.getApplication().runReadAction(() -> {
Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
if (document != null) {
vFile.setContents(document.getText());
}
});
}
@Override
public void showDiffFor(User remoteUser, VFile vFile, String compareWith) {
Project project = getProject(null);
assert project != null;
VirtualFile virtualFile = VFSUtil.getVirtualFile(vFile);
if (virtualFile != null) {
new DiffWindowOpener(project, virtualFile, remoteUser, vFile, compareWith).showDiff();
}
}
@Override
public Change[] getDiff(Object[] src, Object[] dest) {
List<MyChangeAdapter> result = new ArrayList<>();
Diff.Change change;
try {
change = Diff.buildChanges(src, dest);
}
catch (Exception e) {
LOG.warn(e);
return new Change[0];
}
while (change != null) {
result.add(new MyChangeAdapter(change));
change = change.link;
}
return result.toArray(new Change[result.size()]);
}
@Override
public LocalMessage createLocalMessageForIncomingEvent(TransportEvent event) {
final LocalMessage[] result = new LocalMessage[1];
event.accept(new EventVisitor(){
@SuppressWarnings({"RefusedBequest"})
@Override public void visitStacktraceEvent(StacktraceEvent event) {
result[0] = new IncomingStacktraceMessage(event);
}
@SuppressWarnings({"RefusedBequest"})
@Override public void visitCodePointerEvent(CodePointerEvent event) {
result[0] = new IncomingCodePointerMessage(event, IDEAFacade.this);
}
@SuppressWarnings({"RefusedBequest"})
@Override public void visitMessageEvent(MessageEvent event) {
result[0] = new IncomingLocalMessage(event);
}
});
return result[0];
}
@Override
@Nullable
public LocalMessage createLocalMessageForOutgoingEvent(OwnMessageEvent event) {
final LocalMessage[] result = new LocalMessage[1];
event.accept(new EventVisitor() {
@Override public void visitSendMessageEvent(SendMessageEvent event) {
result[0] = new OutgoingLocalMessage(event.getMessage());
}
@Override public void visitSendCodePointerEvent(SendCodePointerEvent event) {
result[0] = new OutgoingCodePointerLocalMessage(event);
}
});
return result[0];
}
@Override
@Nullable
public String getCurrentProjectId() {
Project project = getProject(null);
if (project != null) {
return IdProvider.getInstance(project).getId();
}
return null;
}
public static Object getData(Component c, String dataId) {
Object result = null;
while (c != null) {
if (c instanceof DataProvider) {
DataProvider provider = (DataProvider) c;
Object data = provider.getData(dataId);
if (data != null) {
result = data;
break;
}
}
c = c.getParent();
}
return result;
}
@Nullable
public static Project getProject(Component component) {
Project res = null;
if (component != null) {
res = (Project) getData(component, CommonDataKeys.PROJECT.getName());
}
else {
IdeFrame[] frames = WindowManagerEx.getInstanceEx().getAllProjectFrames();
for (IdeFrame frame : frames) {
final IdeFrameImpl eachFrame = (IdeFrameImpl)frame;
if (eachFrame.isActive()) {
res = eachFrame.getProject();
if (res != null) break;
}
}
}
if (res == null) {
Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
res = openProjects.length > 0 ? openProjects[0] : null;
}
return res;
}
public static void installPopupMenu(ActionGroup group, Component component, ActionManager actionManager) {
if (actionManager == null) return;
PopupHandler.installPopupHandler((JComponent) component, group, "POPUP", actionManager);
}
public static void installIdeaTreeActions(JTree t) {
TreeUtil.installActions(t);
new TreeSpeedSearch(t);
}
private static class MyChangeAdapter implements Change {
private final Diff.Change myChange1;
MyChangeAdapter(Diff.Change change1) {
myChange1 = change1;
}
@Override
public int getInserted() {
return myChange1.inserted;
}
@Override
public int getDeleted() {
return myChange1.deleted;
}
@Override
public int getSrcLine() {
return myChange1.line0;
}
@Override
public int getDestLine() {
return myChange1.line1;
}
}
public static void main(String[] args) {
IDEAFacade ideaFacade = new IDEAFacade();
//noinspection HardCodedStringLiteral
ideaFacade.askQuestion("title", "some\n<i>question</i>");
}
}