diff --git a/lib/core-0.0.1.jar b/lib/core-0.0.1.jar index 87eb155..6341ff2 100644 Binary files a/lib/core-0.0.1.jar and b/lib/core-0.0.1.jar differ diff --git a/lib/smartqq-0.0.1.jar b/lib/smartqq-0.0.1.jar index c54bf0d..8eba403 100644 Binary files a/lib/smartqq-0.0.1.jar and b/lib/smartqq-0.0.1.jar differ diff --git a/lib/wechat-0.0.1.jar b/lib/wechat-0.0.1.jar index 545c7a9..ff8ecbe 100644 Binary files a/lib/wechat-0.0.1.jar and b/lib/wechat-0.0.1.jar differ diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index c32f1de..56f70c2 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -41,7 +41,7 @@ factoryClass="cn.ieclipse.smartim.IMWindowFactory" icon="/icons/im.png"> - + diff --git a/resources/icons/broadcast.png b/resources/icons/broadcast.png new file mode 100644 index 0000000..ba710b8 Binary files /dev/null and b/resources/icons/broadcast.png differ diff --git a/resources/icons/clear_co.png b/resources/icons/clear_co.png new file mode 100644 index 0000000..559471b Binary files /dev/null and b/resources/icons/clear_co.png differ diff --git a/src/cn/ieclipse/smartim/IMClientFactory.java b/src/cn/ieclipse/smartim/IMClientFactory.java index 358cecb..51ecf88 100644 --- a/src/cn/ieclipse/smartim/IMClientFactory.java +++ b/src/cn/ieclipse/smartim/IMClientFactory.java @@ -15,14 +15,13 @@ */ package cn.ieclipse.smartim; +import com.scienjus.smartqq.client.SmartQQClient; +import io.github.biezhi.wechat.api.WechatClient; + import java.io.File; import java.util.HashMap; import java.util.Map; -import com.scienjus.smartqq.client.SmartQQClient; - -import io.github.biezhi.wechat.api.WechatClient; - /** * 类/接口描述 * diff --git a/src/cn/ieclipse/smartim/IMHistoryManager.java b/src/cn/ieclipse/smartim/IMHistoryManager.java index 466b706..f359686 100644 --- a/src/cn/ieclipse/smartim/IMHistoryManager.java +++ b/src/cn/ieclipse/smartim/IMHistoryManager.java @@ -15,13 +15,14 @@ */ package cn.ieclipse.smartim; +import cn.ieclipse.smartim.helper.FileStorage; +import cn.ieclipse.smartim.settings.SmartIMSettings; + import java.io.File; import java.util.HashMap; import java.util.List; import java.util.Map; -import cn.ieclipse.smartim.helper.FileStorage; - /** * 类/接口描述 * @@ -45,6 +46,8 @@ private FileStorage get(SmartClient client, String uin) { if (fs == null) { File f = new File(client.getWorkDir("history"), uin); fs = new FileStorage(size, f.getAbsolutePath()); + boolean persistent = SmartIMSettings.getInstance().getState().LOG_HISTORY; + fs.setPersistent(persistent); stores.put(uin, fs); } return fs; @@ -61,4 +64,10 @@ public boolean save(SmartClient client, String uin, String rawMsg) { ret = ret && fs.isPersistent() && fs.flush(); return ret; } + + public boolean clear(SmartClient client, String uin) { + FileStorage fs = get(client, uin); + fs.release(); + return true; + } } diff --git a/src/cn/ieclipse/smartim/IMReceiveCallback.java b/src/cn/ieclipse/smartim/IMReceiveCallback.java index 2a0119c..2e75238 100644 --- a/src/cn/ieclipse/smartim/IMReceiveCallback.java +++ b/src/cn/ieclipse/smartim/IMReceiveCallback.java @@ -9,6 +9,7 @@ import cn.ieclipse.smartim.model.impl.AbstractMessage; import cn.ieclipse.smartim.settings.SmartIMSettings; import cn.ieclipse.smartim.views.IMPanel; +import cn.ieclipse.util.EncodeUtils; public abstract class IMReceiveCallback implements ReceiveCallback { protected IMChatConsole lastConsole; @@ -31,7 +32,7 @@ protected void handle(boolean unknown, boolean notify, String msg = getMsgContent(message, from); if (!unknown) { IMHistoryManager.getInstance().save(client, - from.getContact().getUin(), msg); + EncodeUtils.getMd5(contact.getName()), msg); } if (notify) { diff --git a/src/cn/ieclipse/smartim/IMRobotCallback.java b/src/cn/ieclipse/smartim/IMRobotCallback.java index 8eabab0..efb244f 100644 --- a/src/cn/ieclipse/smartim/IMRobotCallback.java +++ b/src/cn/ieclipse/smartim/IMRobotCallback.java @@ -15,25 +15,48 @@ */ package cn.ieclipse.smartim; +import cn.ieclipse.smartim.callback.ModificationCallback; import cn.ieclipse.smartim.callback.ReceiveCallback; import cn.ieclipse.smartim.robot.TuringRobot; +import cn.ieclipse.smartim.settings.SmartIMSettings; +import cn.ieclipse.util.EncodeUtils; /** * 类/接口描述 - * + * * @author Jamling * @date 2017年10月16日 - * + * */ -public abstract class IMRobotCallback implements ReceiveCallback { +public abstract class IMRobotCallback + implements ReceiveCallback, ModificationCallback { public static final String SEP = " "; - protected TuringRobot turingRobot; - + protected TuringRobot turingRobot = new TuringRobot("Turing", 0, null); + public static boolean isEnable() { - return false; + return SmartIMSettings.getInstance().getState().ROBOT_ENABLE; } - + public static String getRobotName() { + return SmartIMSettings.getInstance().getState().ROBOT_NAME; + } + + /** + * 对userId或groupId进行加密 + * + * @param id + * userId + * @return 加密后的md5字串 + */ + public static String encodeUid(String id) { + return EncodeUtils.getMd5(id); + } + + public static String getTuringApiKey() { + String key = SmartIMSettings.getInstance().getState().ROBOT_KEY; + if (key != null && !key.isEmpty()) { + return key; + } return null; } } diff --git a/src/cn/ieclipse/smartim/IMSendCallback.java b/src/cn/ieclipse/smartim/IMSendCallback.java index 21ef268..0c2ac14 100644 --- a/src/cn/ieclipse/smartim/IMSendCallback.java +++ b/src/cn/ieclipse/smartim/IMSendCallback.java @@ -49,10 +49,6 @@ public void onSendResult(int type, String targetId, CharSequence msg, } protected void onSuccess(int type, String targetId, CharSequence msg) { -// SmartClient client = getIMPanel().getClient(); -// String name = client.getAccount().getName(); -// IMHistoryManager.getInstance().save(client, targetId, -// IMUtils.formatHtmlMyMsg(System.currentTimeMillis(), name, msg)); imPanel.notifyUpdateContacts(0, true); } @@ -61,7 +57,6 @@ protected void onFailure(int type, String targetId, CharSequence msg, String s = IMUtils.isEmpty(msg) ? "" : (msg.length() > 20 ? msg.toString().substring(0, 20) + "..." : msg.toString()); - IMChatConsole console = getIMPanel().findConsoleById(targetId, true); String code = ""; if (t != null) { if (t instanceof LogicException) { @@ -72,6 +67,7 @@ protected void onFailure(int type, String targetId, CharSequence msg, ((HttpException) t).getCode()); } } + IMChatConsole console = getIMPanel().findConsoleById(targetId, true); if (console != null) { console.error(String.format("%s 发送失败!%s", msg, code)); } else { diff --git a/src/cn/ieclipse/smartim/IMWindowFactory.java b/src/cn/ieclipse/smartim/IMWindowFactory.java index 5590213..3776bfb 100644 --- a/src/cn/ieclipse/smartim/IMWindowFactory.java +++ b/src/cn/ieclipse/smartim/IMWindowFactory.java @@ -2,10 +2,8 @@ import cn.ieclipse.smartqq.SmartQQPanel; import cn.ieclipse.wechat.WechatPanel; -import com.intellij.openapi.Disposable; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; -import com.intellij.openapi.util.Disposer; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowFactory; import com.intellij.openapi.wm.ToolWindowManager; diff --git a/src/cn/ieclipse/smartim/actions/AbstractAction.java b/src/cn/ieclipse/smartim/actions/AbstractAction.java deleted file mode 100644 index a438ca7..0000000 --- a/src/cn/ieclipse/smartim/actions/AbstractAction.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.ieclipse.smartim.actions; - -import cn.ieclipse.smartim.views.IMPanel; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.project.DumbAwareAction; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; - -/** - * Created by Jamling on 2017/7/12. - */ -public class AbstractAction extends DumbAwareAction { - protected IMPanel imPanel; - - public AbstractAction(@Nullable String text, @Nullable String description, @Nullable Icon icon, IMPanel panel) { - super(text, description, icon); - this.imPanel = panel; - } - - @Override - public void actionPerformed(AnActionEvent anActionEvent) { - - } -} diff --git a/src/cn/ieclipse/smartim/actions/BroadcastAction.java b/src/cn/ieclipse/smartim/actions/BroadcastAction.java new file mode 100644 index 0000000..5b224e1 --- /dev/null +++ b/src/cn/ieclipse/smartim/actions/BroadcastAction.java @@ -0,0 +1,36 @@ +package cn.ieclipse.smartim.actions; + +import cn.ieclipse.smartim.SmartClient; +import cn.ieclipse.smartim.views.IMPanel; +import com.intellij.openapi.actionSystem.AnActionEvent; +import icons.SmartIcons; + +import javax.swing.*; + +/** + * Created by Jamling on 2018/02/23. + */ +public class BroadcastAction extends IMPanelAction { + + public BroadcastAction(IMPanel panel) { + super(panel, "群发", "消息群发", SmartIcons.broadcast); + } + + @Override + public void actionPerformed(AnActionEvent anActionEvent) { + final SmartClient client = imPanel.getClient(); + if (client.isLogin()) { + openDialog(); + } + else { + JOptionPane.showInternalMessageDialog(null, "已断开连接,请重新登录成功后再试"); + } + } + + protected void openDialog() { + + } + + public static String groupMacro = "{group}"; + public static String memberMacro = "{member}"; +} diff --git a/src/cn/ieclipse/smartim/actions/ClearHistoryAction.java b/src/cn/ieclipse/smartim/actions/ClearHistoryAction.java new file mode 100644 index 0000000..9fb4491 --- /dev/null +++ b/src/cn/ieclipse/smartim/actions/ClearHistoryAction.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014-2018 ieclipse.cn. + * + * 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 cn.ieclipse.smartim.actions; + +import cn.ieclipse.smartim.console.IMChatConsole; +import com.intellij.openapi.actionSystem.AnActionEvent; +import icons.SmartIcons; + +/** + * 类/接口描述 + * + * @author Jamling + * @date 2018年2月24日 + */ +public class ClearHistoryAction extends IMChatAction { + + public ClearHistoryAction(IMChatConsole console) { + super(console, "", "Clear history", SmartIcons.clear); + } + + @Override + public void actionPerformed(AnActionEvent anActionEvent) { + if (console != null) { + console.clearHistories(); + } + } +} diff --git a/src/cn/ieclipse/smartim/actions/DisconnectAction.java b/src/cn/ieclipse/smartim/actions/DisconnectAction.java index f70df16..1a39ff1 100644 --- a/src/cn/ieclipse/smartim/actions/DisconnectAction.java +++ b/src/cn/ieclipse/smartim/actions/DisconnectAction.java @@ -7,9 +7,9 @@ /** * Created by Jamling on 2017/11/1. */ -public class DisconnectAction extends AbstractAction { +public class DisconnectAction extends IMPanelAction { public DisconnectAction(IMPanel panel) { - super("Close", "Close the connection", SmartIcons.close, panel); + super(panel, "Close", "Close the connection", SmartIcons.close); } @Override diff --git a/src/cn/ieclipse/smartim/actions/IMChatAction.java b/src/cn/ieclipse/smartim/actions/IMChatAction.java new file mode 100644 index 0000000..7b64b31 --- /dev/null +++ b/src/cn/ieclipse/smartim/actions/IMChatAction.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014-2017 ieclipse.cn. + * + * 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 cn.ieclipse.smartim.actions; + +import cn.ieclipse.smartim.console.IMChatConsole; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAwareAction; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * Created by Jamling on 2017/7/12. + */ +public class IMChatAction extends DumbAwareAction { + protected IMChatConsole console; + + public IMChatAction(IMChatConsole console, @Nullable String text, @Nullable String description, @Nullable Icon icon) { + super(text, description, icon); + this.console = console; + } + + @Override + public void actionPerformed(AnActionEvent anActionEvent) { + + } +} diff --git a/src/cn/ieclipse/smartim/actions/IMPanelAction.java b/src/cn/ieclipse/smartim/actions/IMPanelAction.java new file mode 100644 index 0000000..b54badb --- /dev/null +++ b/src/cn/ieclipse/smartim/actions/IMPanelAction.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014-2017 ieclipse.cn. + * + * 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 cn.ieclipse.smartim.actions; + +import cn.ieclipse.smartim.views.IMPanel; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAwareAction; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * Created by Jamling on 2017/7/12. + */ +public class IMPanelAction extends DumbAwareAction { + protected IMPanel imPanel; + + public IMPanelAction(IMPanel panel, @Nullable String text, @Nullable String description, @Nullable Icon icon) { + super(text, description, icon); + this.imPanel = panel; + } + + @Override + public void actionPerformed(AnActionEvent anActionEvent) { + + } +} diff --git a/src/cn/ieclipse/smartim/actions/LoginAction.java b/src/cn/ieclipse/smartim/actions/LoginAction.java index dd6b454..8a928d5 100644 --- a/src/cn/ieclipse/smartim/actions/LoginAction.java +++ b/src/cn/ieclipse/smartim/actions/LoginAction.java @@ -3,37 +3,28 @@ import cn.ieclipse.smartim.SmartClient; import cn.ieclipse.smartim.callback.impl.DefaultLoginCallback; import cn.ieclipse.smartim.views.IMPanel; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.ui.MessageDialogBuilder; -import com.intellij.openapi.wm.ToolWindow; import icons.SmartIcons; /** * Created by Jamling on 2017/7/11. */ -public class LoginAction extends AnAction implements DumbAware { +public class LoginAction extends IMPanelAction { - private IMPanel smartPanel; - private ToolWindow toolWindow; - - - public LoginAction(IMPanel panel, ToolWindow toolWindow) { - super("Login", "Click to login", SmartIcons.signin); - this.smartPanel = panel; - this.toolWindow = toolWindow; + public LoginAction(IMPanel panel) { + super(panel, "Login", "Click to login", SmartIcons.signin); } @Override public void actionPerformed(AnActionEvent anActionEvent) { - SmartClient client = smartPanel.getClient(); + SmartClient client = imPanel.getClient(); boolean ok = true; if (client.isLogin()) { ok = MessageDialogBuilder.yesNo("", "您已处于登录状态,确定要重新登录吗?").show() == 0; } if (ok) { - client.setLoginCallback(new MyLoginCallback(client, smartPanel)); + client.setLoginCallback(new MyLoginCallback(client, imPanel)); new Thread() { @Override public void run() { @@ -41,7 +32,7 @@ public void run() { } }.start(); } else { - smartPanel.initContacts(); + imPanel.initContacts(); } // // LoginDialog dialog = new LoginDialog(client); diff --git a/src/cn/ieclipse/smartim/actions/TestAction.java b/src/cn/ieclipse/smartim/actions/MockConsoleAction.java similarity index 63% rename from src/cn/ieclipse/smartim/actions/TestAction.java rename to src/cn/ieclipse/smartim/actions/MockConsoleAction.java index 78bb084..e739e6b 100644 --- a/src/cn/ieclipse/smartim/actions/TestAction.java +++ b/src/cn/ieclipse/smartim/actions/MockConsoleAction.java @@ -3,21 +3,16 @@ import cn.ieclipse.smartim.console.MockChatConsole; import cn.ieclipse.smartim.model.impl.AbstractContact; import cn.ieclipse.smartim.views.IMPanel; -import cn.ieclipse.smartqq.SmartQQPanel; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.project.DumbAwareAction; -import com.scienjus.smartqq.model.Friend; import icons.SmartIcons; /** * Created by Jamling on 2017/7/12. */ -public class TestAction extends DumbAwareAction { - IMPanel panel; +public class MockConsoleAction extends IMPanelAction { - public TestAction(IMPanel panel) { - super("Test", "Test", SmartIcons.test); - this.panel = panel; + public MockConsoleAction(IMPanel panel) { + super(panel, "Test", "Test", SmartIcons.test); } @Override @@ -34,8 +29,8 @@ public String getUin() { } }; - MockChatConsole console = new MockChatConsole(contact, panel); + MockChatConsole console = new MockChatConsole(contact, imPanel); console.setName(contact.getName()); - panel.addConsole(console); + imPanel.addConsole(console); } } diff --git a/src/cn/ieclipse/smartim/actions/SendFileAction.java b/src/cn/ieclipse/smartim/actions/SendFileAction.java index c5b1d77..4492418 100644 --- a/src/cn/ieclipse/smartim/actions/SendFileAction.java +++ b/src/cn/ieclipse/smartim/actions/SendFileAction.java @@ -1,9 +1,7 @@ package cn.ieclipse.smartim.actions; import cn.ieclipse.smartim.console.IMChatConsole; -import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.project.DumbAwareAction; import icons.SmartIcons; import javax.swing.*; @@ -11,21 +9,19 @@ import javax.swing.filechooser.FileNameExtensionFilter; import java.io.File; -public class SendFileAction extends DumbAwareAction { - IMChatConsole console; +public class SendFileAction extends IMChatAction { protected String dialogTitle; protected FileNameExtensionFilter filter_image = new FileNameExtensionFilter( "图片文件", "jpg", "gif", "bmp", "jpeg", "png"); protected FileFilter filter; public SendFileAction(IMChatConsole console) { - super("发送", "发送文件", SmartIcons.file); - this.console = console; + super(console, "发送", "发送文件", SmartIcons.file); this.dialogTitle = "请选择要发送的文件"; } - public SendFileAction(String text, String desc, Icon icon) { - super(text , desc, icon); + public SendFileAction(IMChatConsole console, String text, String desc, Icon icon) { + super(console, text , desc, icon); } @Override diff --git a/src/cn/ieclipse/smartim/actions/SendImageAction.java b/src/cn/ieclipse/smartim/actions/SendImageAction.java index 51c4309..4e7005f 100644 --- a/src/cn/ieclipse/smartim/actions/SendImageAction.java +++ b/src/cn/ieclipse/smartim/actions/SendImageAction.java @@ -6,9 +6,8 @@ public class SendImageAction extends SendFileAction { public SendImageAction(IMChatConsole console) { - super("图片", "发送图片", SmartIcons.image); + super(console, "图片", "发送图片", SmartIcons.image); this.filter = filter_image; - this.console = console; } } diff --git a/src/cn/ieclipse/smartim/actions/SendProjectFileAction.java b/src/cn/ieclipse/smartim/actions/SendProjectFileAction.java new file mode 100644 index 0000000..034aead --- /dev/null +++ b/src/cn/ieclipse/smartim/actions/SendProjectFileAction.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014-2017 ieclipse.cn. + * + * 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 cn.ieclipse.smartim.actions; + +import cn.ieclipse.smartim.IMWindowFactory; +import cn.ieclipse.smartim.console.IMChatConsole; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.fileChooser.FileChooser; +import com.intellij.openapi.fileChooser.FileChooserDescriptor; +import com.intellij.openapi.vfs.VirtualFile; +import icons.SmartIcons; + +/** + * 类/接口描述 + * + * @author Jamling + * @date 2017年8月22日 + */ +public class SendProjectFileAction extends SendFileAction { + + public SendProjectFileAction(IMChatConsole console) { + super(console, "Send Project File", + "Send your project(workspace) file to " + console.getName(), SmartIcons.projectFile); + } + + @Override + public void actionPerformed(AnActionEvent e) { + if (!console.enableUpload()) { + console.error("文件发送中,请勿频繁操作"); + return; + } + FileChooserDescriptor descriptor = + new FileChooserDescriptor(true, false, true, true, false, false); + final VirtualFile virtualFile = FileChooser.chooseFile(descriptor, IMWindowFactory.getDefault().getProject(), null); + if (virtualFile == null) { + return; + } + String path = virtualFile.getCanonicalPath(); + if (path != null) { + console.send(path); + } + return; + } + +} diff --git a/src/cn/ieclipse/smartim/actions/SendProjectFileAction2.java b/src/cn/ieclipse/smartim/actions/SendProjectFileAction2.java new file mode 100644 index 0000000..63c32a8 --- /dev/null +++ b/src/cn/ieclipse/smartim/actions/SendProjectFileAction2.java @@ -0,0 +1,55 @@ +package cn.ieclipse.smartim.actions; + +import cn.ieclipse.smartim.console.IMChatConsole; +import com.intellij.ide.actions.GotoActionBase; +import com.intellij.ide.util.gotoByName.ChooseByNameModel; +import com.intellij.ide.util.gotoByName.ChooseByNamePopup; +import com.intellij.ide.util.gotoByName.GotoFileModel; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import icons.SmartIcons; + +import java.io.File; + +/** + * Created by Jamling on 2018/2/27. + */ +public class SendProjectFileAction2 extends GotoActionBase implements DumbAware { + private IMChatConsole console; + + public SendProjectFileAction2(IMChatConsole console) { + this.console = console; + getTemplatePresentation().setIcon(SmartIcons.projectFile); + getTemplatePresentation().setText("发送工程中的文件"); + } + + @Override + protected void gotoActionPerformed(AnActionEvent anActionEvent) { + Project project = anActionEvent.getData(CommonDataKeys.PROJECT); + ChooseByNameModel model = new GotoFileModel(project); + showNavigationPopup(anActionEvent, model, new Callback(), false); + } + + private class Callback extends GotoActionCallback { + + @Override + public void elementChosen(ChooseByNamePopup chooseByNamePopup, Object o) { + if (o != null && o instanceof PsiFile) { + PsiFile file = (PsiFile) o; + VirtualFile vf = file.getVirtualFile(); + if (vf != null) { + File f = new File(vf.getCanonicalPath()); + if (f.exists()) { + console.sendFile(f.getAbsolutePath()); + } else { + console.send(vf.getCanonicalPath()); + } + } + } + } + } +} diff --git a/src/cn/ieclipse/smartim/actions/SettingAction.java b/src/cn/ieclipse/smartim/actions/SettingAction.java index d2d2034..a109020 100644 --- a/src/cn/ieclipse/smartim/actions/SettingAction.java +++ b/src/cn/ieclipse/smartim/actions/SettingAction.java @@ -2,21 +2,16 @@ import cn.ieclipse.smartim.settings.SmartSettingsPanel; import cn.ieclipse.smartim.views.IMPanel; -import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.options.ShowSettingsUtil; -import com.intellij.openapi.project.DumbAwareAction; import icons.SmartIcons; /** * Created by Jamling on 2017/7/11. */ -public class SettingAction extends DumbAwareAction { - - IMPanel imPanel; - +public class SettingAction extends IMPanelAction { public SettingAction(IMPanel panel) { - super("设置", "首选项及设置", SmartIcons.settings); + super(panel, "设置", "首选项及设置", SmartIcons.settings); this.imPanel = panel; } diff --git a/src/cn/ieclipse/smartim/common/IMUtils.java b/src/cn/ieclipse/smartim/common/IMUtils.java index 497e2c0..c2d8cce 100644 --- a/src/cn/ieclipse/smartim/common/IMUtils.java +++ b/src/cn/ieclipse/smartim/common/IMUtils.java @@ -16,6 +16,7 @@ package cn.ieclipse.smartim.common; import cn.ieclipse.util.FileUtils; +import cn.ieclipse.util.Patterns; import cn.ieclipse.util.StringUtils; import java.io.File; @@ -29,19 +30,16 @@ /** * 类/接口描述 - * + * * @author Jamling * @date 2017年8月14日 - * */ public class IMUtils { - + /** * Get file name from file path * - * @param path - * file path - * + * @param path file path * @return file name */ public static String getName(String path) { @@ -49,39 +47,43 @@ public static String getName(String path) { String name = f.getName(); return name; } - + public static String formatFileSize(long length) { if (length > (1 << 20)) { return length / (1 << 20) + "M"; - } - else if (length > (1 << 10)) { + } else if (length > (1 << 10)) { return length / (1 << 10) + "K"; } return length + "B"; } - + public static boolean isEmpty(CharSequence text) { return text == null || text.length() == 0; } - + public static boolean isEmpty(Collection list) { return list == null || list.isEmpty(); } - - public static String formatMsg(long time, String name, CharSequence msg) { - String s1 = new SimpleDateFormat("HH:mm:ss").format(time); - return String.format("%s %s: %s\n", s1, name, msg); - } + public static String encodeHtml(String msg) { if (StringUtils.isEmpty(msg)) { return ""; - } - else { + } else { return StringUtils.encodeXml(msg); } } + public static String formatMsg(long time, String name, CharSequence msg) { + String s1 = new SimpleDateFormat("HH:mm:ss").format(time); + return String.format("%s %s: %s\n", s1, name, msg); + } + + public static boolean isMySendMsg(String raw) { + return raw.matches("^\\d{2}:\\d{2}:\\d{2} [.\\s\\S]*") + || raw.startsWith(" groups = new ArrayList<>(); @@ -152,8 +149,7 @@ private static String autoLink(String input) { if (c == '=') { continue; } - } - else if (c == '>') { + } else if (c == '>') { continue; } } diff --git a/src/cn/ieclipse/smartim/common/Notifications.java b/src/cn/ieclipse/smartim/common/Notifications.java index 1389201..02836a5 100644 --- a/src/cn/ieclipse/smartim/common/Notifications.java +++ b/src/cn/ieclipse/smartim/common/Notifications.java @@ -6,7 +6,6 @@ import com.intellij.notification.Notification; import com.intellij.notification.NotificationDisplayType; import com.intellij.notification.NotificationType; -import com.intellij.openapi.ui.popup.Balloon; /** * Created by Jamling on 2017/10/31. diff --git a/src/cn/ieclipse/smartim/common/WrapHTMLFactory.java b/src/cn/ieclipse/smartim/common/WrapHTMLFactory.java index 9661799..9f06da8 100644 --- a/src/cn/ieclipse/smartim/common/WrapHTMLFactory.java +++ b/src/cn/ieclipse/smartim/common/WrapHTMLFactory.java @@ -15,7 +15,7 @@ */ package cn.ieclipse.smartim.common; -import javax.swing.SizeRequirements; +import javax.swing.*; import javax.swing.text.BadLocationException; import javax.swing.text.Element; import javax.swing.text.GlyphView; diff --git a/src/cn/ieclipse/smartim/console/IMChatConsole.java b/src/cn/ieclipse/smartim/console/IMChatConsole.java index c4d56b6..b3d589d 100644 --- a/src/cn/ieclipse/smartim/console/IMChatConsole.java +++ b/src/cn/ieclipse/smartim/console/IMChatConsole.java @@ -1,19 +1,18 @@ package cn.ieclipse.smartim.console; -import cn.ieclipse.smartim.AbstractSmartClient; import cn.ieclipse.smartim.IMHistoryManager; import cn.ieclipse.smartim.SmartClient; -import cn.ieclipse.smartim.actions.ScrollLockAction; -import cn.ieclipse.smartim.actions.SendFileAction; -import cn.ieclipse.smartim.actions.SendImageAction; +import cn.ieclipse.smartim.actions.*; import cn.ieclipse.smartim.common.IMUtils; import cn.ieclipse.smartim.common.LOG; import cn.ieclipse.smartim.common.WrapHTMLFactory; import cn.ieclipse.smartim.idea.EditorUtils; import cn.ieclipse.smartim.model.IContact; +import cn.ieclipse.smartim.model.impl.AbstractContact; import cn.ieclipse.smartim.settings.SmartIMSettings; import cn.ieclipse.smartim.views.IMPanel; import cn.ieclipse.util.BareBonesBrowserLaunch; +import cn.ieclipse.util.EncodeUtils; import cn.ieclipse.util.StringUtils; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionToolbar; @@ -52,10 +51,13 @@ public IMChatConsole(IContact target, IMPanel imPanel) { this.uin = target.getUin(); this.imPanel = imPanel; initUI(); - loadHistories(); + new Thread() { + public void run() { + loadHistories(); + } + }.start(); } - public SmartClient getClient() { return imPanel.getClient(); } @@ -65,7 +67,7 @@ public SmartClient getClient() { public abstract void post(final String msg); public String getHistoryFile() { - return uin; + return EncodeUtils.getMd5(contact.getName()); } public String getUin() { @@ -96,6 +98,17 @@ public void loadHistories() { } } + public void clearHistories() { + IMHistoryManager.getInstance().clear(getClient(), getHistoryFile()); + historyWidget.setText(""); + } + + public void clearUnread() { + if (contact != null && contact instanceof AbstractContact) { + ((AbstractContact) contact).clearUnRead(); + } + } + public boolean hideMyInput() { return false; } @@ -121,7 +134,7 @@ public void send(final String input) { String msg = IMUtils.formatHtmlMyMsg(System.currentTimeMillis(), name, input); if (!hideMyInput()) { insertDocument(msg); - IMHistoryManager.getInstance().save(client, getUin(), msg); + IMHistoryManager.getInstance().save(client, getHistoryFile(), msg); } new Thread() { @Override @@ -141,6 +154,7 @@ public void run() { LOG.error("发送文件失败 : " + e); LOG.sendNotification("发送文件失败", String.format("文件:%s(%s)", file, e.getMessage())); + error(String.format("发送文件失败:%s(%s)", file, e.getMessage())); } finally { uploadLock = false; } @@ -157,12 +171,7 @@ public void error(Throwable e) { } public void error(final String msg) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - insertDocument(String.format("
%s
", msg)); - } - }); + insertDocument(String.format("
%s
", msg)); } private void createUIComponents() { @@ -170,12 +179,7 @@ private void createUIComponents() { } public void write(final String msg) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - insertDocument(msg); - } - }); + insertDocument(msg); } protected JBSplitter splitter; @@ -236,7 +240,10 @@ protected void initToolBar() { protected void initToolBar(DefaultActionGroup group) { group.add(new SendImageAction(this)); group.add(new SendFileAction(this)); + // group.add(new SendProjectFileAction(this)); + group.add(new SendProjectFileAction2(this)); group.add(new ScrollLockAction(this)); + group.add(new ClearHistoryAction(this)); } public class SendAction extends AbstractAction { @@ -329,20 +336,25 @@ protected boolean hyperlinkActivated(String desc) { return false; } - protected void insertDocument(String msg) { - try { - HTMLEditorKit kit = (HTMLEditorKit) historyWidget.getEditorKit(); - HTMLDocument doc = (HTMLDocument) historyWidget.getDocument(); - // historyWidget.getDocument().insertString(len - offset, - // trimMsg(msg), null); - // Element root = doc.getDefaultRootElement(); - // Element body = root.getElement(1); - // doc.insertBeforeEnd(body, msg); - int pos = historyWidget.getCaretPosition(); - kit.insertHTML(doc, doc.getLength(), msg, 0, 0, null); - historyWidget.setCaretPosition(scrollLock ? pos : doc.getLength()); - } catch (Exception e) { - e.printStackTrace(); - } + protected void insertDocument(final String msg) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + HTMLEditorKit kit = (HTMLEditorKit) historyWidget.getEditorKit(); + HTMLDocument doc = (HTMLDocument) historyWidget.getDocument(); + // historyWidget.getDocument().insertString(len - offset, + // trimMsg(msg), null); + // Element root = doc.getDefaultRootElement(); + // Element body = root.getElement(1); + // doc.insertBeforeEnd(body, msg); + int pos = historyWidget.getCaretPosition(); + kit.insertHTML(doc, doc.getLength(), msg, 0, 0, null); + historyWidget.setCaretPosition(scrollLock ? pos : doc.getLength()); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); } } diff --git a/src/cn/ieclipse/smartim/console/MockChatConsole.java b/src/cn/ieclipse/smartim/console/MockChatConsole.java index a190783..f8a4862 100644 --- a/src/cn/ieclipse/smartim/console/MockChatConsole.java +++ b/src/cn/ieclipse/smartim/console/MockChatConsole.java @@ -35,9 +35,13 @@ public void loadHistories() { @Override public void send(String input) { - String msg = IMUtils.formatHtmlMyMsg(System.currentTimeMillis(), "Me", input); + String msg = IMUtils.formatHtmlMyMsg(System.currentTimeMillis(), "Me", + input); if (!hideMyInput()) { insertDocument(msg); } + String msg2 = IMUtils.formatHtmlMsg(false, false, + System.currentTimeMillis(), "Me", input); + write(msg2); } } diff --git a/src/cn/ieclipse/smartim/dialogs/BroadcastDialog.java b/src/cn/ieclipse/smartim/dialogs/BroadcastDialog.java new file mode 100644 index 0000000..d45734c --- /dev/null +++ b/src/cn/ieclipse/smartim/dialogs/BroadcastDialog.java @@ -0,0 +1,137 @@ +package cn.ieclipse.smartim.dialogs; + +import cn.ieclipse.smartim.common.IMUtils; +import cn.ieclipse.smartim.views.CheckBoxTreeCellRenderer; +import cn.ieclipse.smartim.views.CheckBoxTreeNodeSelectionListener; +import cn.ieclipse.smartim.views.IMPanel; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + +public class BroadcastDialog extends JDialog implements ActionListener { + + private final JPanel contentPanel = new JPanel(); + protected JTextArea text; + protected JTabbedPane tabHost; + protected IMPanel imPanel; + + /** + * Launch the application. + */ + public static void main(String[] args) { + try { + BroadcastDialog dialog = new BroadcastDialog(null); + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Create the dialog. + */ + public BroadcastDialog(IMPanel imPanel) { + this.imPanel = imPanel; + setLocationRelativeTo(null); + setSize(400, 300); + getContentPane().setLayout(new BorderLayout()); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + getContentPane().add(contentPanel, BorderLayout.CENTER); + contentPanel.setLayout(new BorderLayout(0, 0)); + { + text = new JTextArea(); + text.setRows(4); + text.setLineWrap(true); + JScrollPane scrollPane = new JScrollPane(text); + contentPanel.add(scrollPane, BorderLayout.NORTH); + } + { + tabHost = new JTabbedPane(JTabbedPane.TOP); + contentPanel.add(tabHost, BorderLayout.CENTER); + } + { + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); + getContentPane().add(buttonPane, BorderLayout.SOUTH); + { + JButton okButton = new JButton("OK"); + okButton.setActionCommand("OK"); + buttonPane.add(okButton); + getRootPane().setDefaultButton(okButton); + okButton.addActionListener(this); + } + { + JButton cancelButton = new JButton("Cancel"); + cancelButton.setActionCommand("Cancel"); + buttonPane.add(cancelButton); + cancelButton.addActionListener(this); + } + } + initTab(tabHost); + } + + protected void initTab(JTabbedPane host) { + + } + + protected void initTrees(JTree... trees) { + for (JTree tree : trees) { + if (tree != null) { + initTree(tree); + } + } + } + + protected void initTree(JTree tree) { + tree.setCellRenderer(new CheckBoxTreeCellRenderer()); + tree.setShowsRootHandles(false); + tree.setRootVisible(false); + tree.addMouseListener(new CheckBoxTreeNodeSelectionListener()); + } + + public void updateTrees(JTree... trees) { + for (JTree tree : trees) { + if (tree != null) { + tree.updateUI(); + } + } + } + + @Override + public void actionPerformed(ActionEvent e) { + if ("OK".equals(e.getActionCommand())) { + okPressed(); + } + else if ("Cancel".equals(e.getActionCommand())) { + + } + dispose(); + } + + protected void okPressed() { + final String text = this.text.getText().trim(); + if (IMUtils.isEmpty(text)) { + return; + } + final List targets = new ArrayList<>(); + addTarget(targets); + new Thread() { + public void run() { + sendInternal(text, targets); + }; + }.start(); + } + + protected void addTarget(final List targets) { + + } + + protected void sendInternal(String text, List targets) { + } +} diff --git a/src/cn/ieclipse/smartim/dialogs/ReviewDialog.java b/src/cn/ieclipse/smartim/dialogs/ReviewDialog.java index a231651..fbeb9e2 100644 --- a/src/cn/ieclipse/smartim/dialogs/ReviewDialog.java +++ b/src/cn/ieclipse/smartim/dialogs/ReviewDialog.java @@ -3,11 +3,8 @@ import cn.ieclipse.smartim.IMWindowFactory; import cn.ieclipse.smartim.console.IMChatConsole; import cn.ieclipse.smartim.views.IMPanel; -import cn.ieclipse.smartqq.SmartQQPanel; -import com.intellij.openapi.actionSystem.ActionGroupUtil; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.ui.content.Content; diff --git a/src/cn/ieclipse/smartim/idea/EditorUtils.java b/src/cn/ieclipse/smartim/idea/EditorUtils.java index b140949..08c0eff 100644 --- a/src/cn/ieclipse/smartim/idea/EditorUtils.java +++ b/src/cn/ieclipse/smartim/idea/EditorUtils.java @@ -1,23 +1,14 @@ package cn.ieclipse.smartim.idea; import cn.ieclipse.smartim.IMWindowFactory; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.ScrollType; -import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ProjectFileIndex; -import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiJavaFile; /** * Created by Jamling on 2018/1/2. diff --git a/src/cn/ieclipse/smartim/settings/GeneralPanel.form b/src/cn/ieclipse/smartim/settings/GeneralPanel.form new file mode 100644 index 0000000..8bdc024 --- /dev/null +++ b/src/cn/ieclipse/smartim/settings/GeneralPanel.form @@ -0,0 +1,169 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/cn/ieclipse/smartim/settings/GeneralPanel.java b/src/cn/ieclipse/smartim/settings/GeneralPanel.java new file mode 100644 index 0000000..df9d07e --- /dev/null +++ b/src/cn/ieclipse/smartim/settings/GeneralPanel.java @@ -0,0 +1,149 @@ +package cn.ieclipse.smartim.settings; + +import cn.ieclipse.smartim.common.LOG; +import com.google.gson.Gson; +import com.intellij.ide.plugins.IdeaPluginDescriptor; +import com.intellij.ide.plugins.PluginManager; +import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import okhttp3.Call; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * Created by Jamling on 2017/7/11. + */ +public class GeneralPanel implements Configurable { + private TextFieldWithBrowseButton send; + private JCheckBox chkNotify; + private JCheckBox chkNotifyUnread; + private JCheckBox chkSendBtn; + private JPanel panel; + private JCheckBox chkNotifyGroupMsg; + private JCheckBox chkNotifyUnknown; + private JCheckBox chkHideMyInput; + private JLabel linkUpdate; + private JLabel linkAbout; + private JCheckBox chkHistory; + private SmartIMSettings settings; + + private String update_url = "http://api.ieclipse.cn/smartqq/index/notice?p=intellij"; + private String about_url = "http://api.ieclipse.cn/smartqq/index/about"; + + public GeneralPanel(SmartIMSettings settings) { + this.settings = settings; + linkUpdate.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + checkUpdate(); + } + }); + linkAbout.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + cn.ieclipse.util.BareBonesBrowserLaunch.openURL(about_url); + } + }); + } + + @Nls + @Override + public String getDisplayName() { + return "SmartIM"; + } + + @Nullable + @Override + public String getHelpTopic() { + return null; + } + + @Nullable + @Override + public JComponent createComponent() { + return panel; + } + + @Override + public boolean isModified() { + return chkNotify.isSelected() != settings.getState().NOTIFY_MSG + || chkNotifyUnread.isSelected() != settings.getState().NOTIFY_UNREAD + || chkSendBtn.isSelected() != settings.getState().SHOW_SEND + || chkNotifyGroupMsg.isSelected() != settings.getState().NOTIFY_GROUP_MSG + || chkNotifyUnknown.isSelected() != settings.getState().NOTIFY_UNKNOWN + || chkHideMyInput.isSelected() != settings.getState().HIDE_MY_INPUT + || chkHistory.isSelected() != settings.getState().LOG_HISTORY; + } + + @Override + public void apply() throws ConfigurationException { + settings.getState().NOTIFY_MSG = chkNotify.isSelected(); + settings.getState().NOTIFY_UNREAD = chkNotifyUnread.isSelected(); + settings.getState().SHOW_SEND = chkSendBtn.isSelected(); + settings.getState().NOTIFY_GROUP_MSG = chkNotifyGroupMsg.isSelected(); + settings.getState().NOTIFY_UNKNOWN = chkNotifyUnknown.isSelected(); + settings.getState().HIDE_MY_INPUT = chkHideMyInput.isSelected(); + settings.getState().LOG_HISTORY = chkHistory.isSelected(); + } + + @Override + public void reset() { + chkNotify.setSelected(settings.getState().NOTIFY_MSG); + chkNotifyGroupMsg.setSelected(settings.getState().NOTIFY_GROUP_MSG); + chkSendBtn.setSelected(settings.getState().SHOW_SEND); + chkNotifyUnread.setSelected(settings.getState().NOTIFY_UNREAD); + chkNotifyUnknown.setSelected(settings.getState().NOTIFY_UNKNOWN); + chkHideMyInput.setSelected(settings.getState().HIDE_MY_INPUT); + chkHistory.setSelected(settings.getState().LOG_HISTORY); + } + + @Override + public void disposeUIResources() { + + } + + private void checkUpdate() { + new Thread() { + public void run() { + try { + okhttp3.Request.Builder builder = (new okhttp3.Request.Builder()) + .url(update_url).get(); + Request request = builder.build(); + Call call = new OkHttpClient().newCall(request); + Response response = call.execute(); + String json = response.body().string(); + //LOG.info(json); + if (response.code() == 200) { + final UpdateInfo info = new Gson().fromJson(json, + UpdateInfo.class); + final IdeaPluginDescriptor descriptor = PluginManager.getPlugin(PluginId.findId("cn.ieclipse.smartqq.intellij")); + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (descriptor != null && descriptor.getVersion().equals(info.latest)) { + JOptionPane.showMessageDialog(null, "已是最新版本"); + return; + } + cn.ieclipse.smartim.common.Notifications.notify(info.latest, info.desc); + JOptionPane.showMessageDialog(null, "发现新版本" + info.latest + "请在File->Settings->Plugins插件页中更新SmartQQ"); + } + }); + } + } catch (Exception ex) { + LOG.error("检查SmartIM最新版本", ex); + } + } + }.start(); + } +} diff --git a/src/cn/ieclipse/smartim/settings/RobotPanel.form b/src/cn/ieclipse/smartim/settings/RobotPanel.form new file mode 100644 index 0000000..952726c --- /dev/null +++ b/src/cn/ieclipse/smartim/settings/RobotPanel.form @@ -0,0 +1,125 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/cn/ieclipse/smartim/settings/RobotPanel.java b/src/cn/ieclipse/smartim/settings/RobotPanel.java new file mode 100644 index 0000000..d7b20a2 --- /dev/null +++ b/src/cn/ieclipse/smartim/settings/RobotPanel.java @@ -0,0 +1,66 @@ +package cn.ieclipse.smartim.settings; + +import javax.swing.*; +import java.awt.*; + +/** + * Created by Jamling on 2018/2/24. + */ +public class RobotPanel { + private JCheckBox chkRobot; + private JTextField textRobotName; + private JComboBox comboRobot; + private JTextField textApiKey; + private JTextField textWelcome; + private JCheckBox chkGroupAny; + private JCheckBox chkFriendAny; + private JTextField textReplyEmpty; + private JPanel panel; + private SmartIMSettings settings; + + public RobotPanel(SmartIMSettings settings) { + this.settings = settings; + } + + public Component createComponent() { + return panel; + } + + public boolean isModified() { + return settings.getState().ROBOT_TYPE != comboRobot.getSelectedIndex() + || settings.getState().ROBOT_ENABLE != chkRobot.isSelected() + || settings.getState().ROBOT_FRIEND_ANY != chkFriendAny.isSelected() + || settings.getState().ROBOT_GROUP_ANY != chkGroupAny.isSelected() + || !settings.getState().ROBOT_KEY.equals(textApiKey.getText().trim()) + || !settings.getState().ROBOT_REPLY_EMPTY.equals(textReplyEmpty.getText().trim()) + || !settings.getState().ROBOT_NAME.equals(textRobotName.getText().trim()) + || !settings.getState().ROBOT_GROUP_WELCOME.equals(textWelcome.getText().trim()) + ; + } + + public void reset() { + int idx = settings.getState().ROBOT_TYPE; + if (idx >= 0 && idx < comboRobot.getItemCount()) { + comboRobot.setSelectedIndex(idx); + } + chkRobot.setSelected(settings.getState().ROBOT_ENABLE); + chkFriendAny.setSelected(settings.getState().ROBOT_FRIEND_ANY); + chkGroupAny.setSelected(settings.getState().ROBOT_GROUP_ANY); + textApiKey.setText(settings.getState().ROBOT_KEY); + textReplyEmpty.setText(settings.getState().ROBOT_REPLY_EMPTY); + textRobotName.setText(settings.getState().ROBOT_NAME); + textWelcome.setText(settings.getState().ROBOT_GROUP_WELCOME); + } + + public void apply() { + settings.getState().ROBOT_TYPE = comboRobot.getSelectedIndex(); + settings.getState().ROBOT_ENABLE = chkRobot.isSelected(); + settings.getState().ROBOT_FRIEND_ANY = chkFriendAny.isSelected(); + settings.getState().ROBOT_GROUP_ANY = chkGroupAny.isSelected(); + settings.getState().ROBOT_KEY = textApiKey.getText().trim(); + settings.getState().ROBOT_REPLY_EMPTY = textReplyEmpty.getText() + .trim(); + settings.getState().ROBOT_NAME = textRobotName.getText().trim(); + settings.getState().ROBOT_GROUP_WELCOME = textWelcome.getText().trim(); + } +} diff --git a/src/cn/ieclipse/smartim/settings/SmartIMSettings.java b/src/cn/ieclipse/smartim/settings/SmartIMSettings.java index 8d1953f..63c9fe8 100644 --- a/src/cn/ieclipse/smartim/settings/SmartIMSettings.java +++ b/src/cn/ieclipse/smartim/settings/SmartIMSettings.java @@ -1,6 +1,9 @@ package cn.ieclipse.smartim.settings; -import com.intellij.openapi.components.*; +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; import org.jetbrains.annotations.Nullable; /** @@ -53,5 +56,23 @@ public static class State { public boolean NOTIFY_UNKNOWN = false; public boolean HIDE_MY_INPUT = true; + public boolean LOG_HISTORY = true; + + public boolean ROBOT_ENABLE = false; + public String ROBOT_NAME = ""; + public int ROBOT_TYPE = 0; + public String ROBOT_KEY = ""; + public String ROBOT_GROUP_WELCOME = "欢迎{user} {memo}"; + public boolean ROBOT_GROUP_ANY = false; + public boolean ROBOT_FRIEND_ANY = false; + public String ROBOT_REPLY_EMPTY = ""; + + public boolean QN_ENABLE = false; + public String QN_BUCKET = ""; + public int QN_ZONE = 0; + public String QN_DOMAIN = ""; + public String QN_AK = ""; + public String QN_SK = ""; + public boolean QN_TS = false; } } diff --git a/src/cn/ieclipse/smartim/settings/SmartSettingsPanel.form b/src/cn/ieclipse/smartim/settings/SmartSettingsPanel.form index fcbd181..2161894 100644 --- a/src/cn/ieclipse/smartim/settings/SmartSettingsPanel.form +++ b/src/cn/ieclipse/smartim/settings/SmartSettingsPanel.form @@ -1,160 +1,46 @@
- + - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - + - - - - - + + + + + - + - - - - + + + + - - - - - - - - - - + diff --git a/src/cn/ieclipse/smartim/settings/SmartSettingsPanel.java b/src/cn/ieclipse/smartim/settings/SmartSettingsPanel.java index a3cd391..9e74188 100644 --- a/src/cn/ieclipse/smartim/settings/SmartSettingsPanel.java +++ b/src/cn/ieclipse/smartim/settings/SmartSettingsPanel.java @@ -1,58 +1,38 @@ package cn.ieclipse.smartim.settings; -import cn.ieclipse.smartim.common.LOG; -import com.google.gson.Gson; -import com.intellij.ide.plugins.IdeaPluginDescriptor; -import com.intellij.ide.plugins.PluginManager; -import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.ui.TextFieldWithBrowseButton; -import okhttp3.Call; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.components.JBTabbedPane; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; /** - * Created by Jamling on 2017/7/11. + * Created by Jamling on 2018/2/27. */ public class SmartSettingsPanel implements Configurable { - private TextFieldWithBrowseButton send; - private JCheckBox chkNotify; - private JCheckBox chkNotifyUnread; - private JCheckBox chkSendBtn; private JPanel panel; - private JCheckBox chkNotifyGroupMsg; - private JCheckBox chkNotifyUnknown; - private JCheckBox chkHideMyInput; - private JLabel linkUpdate; - private JLabel linkAbout; + private JBTabbedPane tabHost; + private JBScrollPane scroll1; + private JBScrollPane scroll2; + private JBScrollPane scroll3; private SmartIMSettings settings; - - private String update_url = "http://api.ieclipse.cn/smartqq/index/notice?p=intellij"; - private String about_url = "http://api.ieclipse.cn/smartqq/index/about"; + private GeneralPanel generalPanel; + private RobotPanel robotPanel; + private UploadPanel uploadPanel; public SmartSettingsPanel() { settings = SmartIMSettings.getInstance(); - linkUpdate.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - super.mouseClicked(e); - checkUpdate(); - } - }); - linkAbout.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - cn.ieclipse.util.BareBonesBrowserLaunch.openURL(about_url); - } - }); + generalPanel = new GeneralPanel(settings); + scroll1.setViewportView(generalPanel.createComponent()); + + robotPanel = new RobotPanel(settings); + scroll2.setViewportView(robotPanel.createComponent()); + + uploadPanel = new UploadPanel(settings); + scroll3.setViewportView(uploadPanel); } @Nls @@ -75,75 +55,26 @@ public JComponent createComponent() { @Override public boolean isModified() { - return chkNotify.isSelected() != settings.getState().NOTIFY_MSG - || chkNotifyUnread.isSelected() != settings.getState().NOTIFY_UNREAD - || chkSendBtn.isSelected() != settings.getState().SHOW_SEND - || chkNotifyGroupMsg.isSelected() != settings.getState().NOTIFY_GROUP_MSG - || chkNotifyUnknown.isSelected() != settings.getState().NOTIFY_UNKNOWN - || chkHideMyInput.isSelected() != settings.getState().HIDE_MY_INPUT - ; + return generalPanel.isModified() || robotPanel.isModified() || uploadPanel.isModified(); } @Override public void apply() throws ConfigurationException { - settings.getState().NOTIFY_MSG = chkNotify.isSelected(); - settings.getState().NOTIFY_UNREAD = chkNotifyUnread.isSelected(); - settings.getState().SHOW_SEND = chkSendBtn.isSelected(); - settings.getState().NOTIFY_GROUP_MSG = chkNotifyGroupMsg.isSelected(); - settings.getState().NOTIFY_UNKNOWN = chkNotifyUnknown.isSelected(); - settings.getState().HIDE_MY_INPUT = chkHideMyInput.isSelected(); + generalPanel.apply(); + robotPanel.apply(); + uploadPanel.apply(); settings.loadState(settings.getState()); } @Override public void reset() { - chkNotify.setSelected(settings.getState().NOTIFY_MSG); - chkNotifyGroupMsg.setSelected(settings.getState().NOTIFY_GROUP_MSG); - chkSendBtn.setSelected(settings.getState().SHOW_SEND); - chkNotifyUnread.setSelected(settings.getState().NOTIFY_UNREAD); - chkNotifyUnknown.setSelected(settings.getState().NOTIFY_UNKNOWN); - chkHideMyInput.setSelected(settings.getState().HIDE_MY_INPUT); + generalPanel.reset(); + robotPanel.reset(); + uploadPanel.reset(); } @Override public void disposeUIResources() { } - - private void checkUpdate() { - new Thread() { - public void run() { - try { - okhttp3.Request.Builder builder = (new okhttp3.Request.Builder()) - .url(update_url).get(); - Request request = builder.build(); - Call call = new OkHttpClient().newCall(request); - Response response = call.execute(); - String json = response.body().string(); - //LOG.info(json); - if (response.code() == 200) { - final UpdateInfo info = new Gson().fromJson(json, - UpdateInfo.class); - final IdeaPluginDescriptor descriptor = PluginManager.getPlugin(PluginId.findId("cn.ieclipse.smartqq.intellij")); - - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (descriptor != null && descriptor.getVersion().equals(info.latest)) { - JOptionPane.showMessageDialog(null, "已是最新版本"); - return; - } - cn.ieclipse.smartim.common.Notifications.notify(info.latest, info.desc); - JOptionPane.showMessageDialog(null, "发现新版本" + info.latest + "请在File->Settings->Plugins插件页中更新SmartQQ"); - } - }); - } - } catch (Exception ex) { - LOG.error("检查SmartIM最新版本", ex); - } - } - - ; - }.start(); - } } diff --git a/src/cn/ieclipse/smartim/settings/UploadPanel.java b/src/cn/ieclipse/smartim/settings/UploadPanel.java new file mode 100644 index 0000000..5e3e850 --- /dev/null +++ b/src/cn/ieclipse/smartim/settings/UploadPanel.java @@ -0,0 +1,188 @@ +package cn.ieclipse.smartim.settings; + +import com.intellij.openapi.ui.ComboBox; + +import javax.swing.*; +import java.awt.*; + +public class UploadPanel extends JPanel { + + private JCheckBox chkEnable; + private JComboBox comboZone; + private JTextField textAccessKey; + private JTextField textSecretKey; + private JTextField textBucket; + private JTextField textDomain; + private JCheckBox chkTs; + + private SmartIMSettings settings; + + public static final String[][] ZONE_VALUE = {{"自动", "autoZone"}, + {"华东", "huadong"}, {"华北", "huabei"}, {"华南", "huanan"}, + {"北美", "beimei"}}; + + public static final String[] ZONE_LABEL = {"自动", "华东", "华北", "华南", "北美"}; + + /** + * Create the panel. + */ + public UploadPanel(SmartIMSettings settings) { + this.settings = settings; + GridBagLayout gridBagLayout = new GridBagLayout(); + gridBagLayout.columnWidths = new int[]{0, 0}; + gridBagLayout.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0}; + gridBagLayout.columnWeights = new double[]{0.0, 1.0}; + gridBagLayout.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, Double.MIN_VALUE}; + setLayout(gridBagLayout); + + JTextArea lblNewLabel = new JTextArea( + "SmartQQ文件传输详情请参考http://api.ieclipse.cn/smartqq\r\n如果您未设置七牛云储存,发送的文件将上传到本人私有储存空间(temp.ieclipse.cn,文件大小有限制而且非永久保存),建议您注册七牛云来实现文件传输\r\n注:如果使用您自己的七牛云,带*的accessKey和secretKey必填,否则不生效哦"); + lblNewLabel.setLineWrap(true); + lblNewLabel.setEnabled(false); + lblNewLabel.setEditable(false); + GridBagConstraints gbc_lblNewLabel = new GridBagConstraints(); + gbc_lblNewLabel.fill = GridBagConstraints.BOTH; + gbc_lblNewLabel.insets = new Insets(5, 5, 5, 0); + gbc_lblNewLabel.gridwidth = 2; + gbc_lblNewLabel.gridx = 0; + gbc_lblNewLabel.gridy = 0; + add(lblNewLabel, gbc_lblNewLabel); + + chkEnable = new JCheckBox("启用七牛云存储"); + GridBagConstraints gbc_chkEnable = new GridBagConstraints(); + gbc_chkEnable.anchor = GridBagConstraints.WEST; + gbc_chkEnable.insets = new Insets(0, 0, 5, 0); + gbc_chkEnable.gridwidth = 2; + gbc_chkEnable.gridx = 0; + gbc_chkEnable.gridy = 1; + add(chkEnable, gbc_chkEnable); + + JLabel lblNewLabel_1 = new JLabel("机房"); + GridBagConstraints gbc_lblNewLabel_1 = new GridBagConstraints(); + gbc_lblNewLabel_1.anchor = GridBagConstraints.EAST; + gbc_lblNewLabel_1.insets = new Insets(0, 0, 5, 5); + gbc_lblNewLabel_1.gridx = 0; + gbc_lblNewLabel_1.gridy = 2; + add(lblNewLabel_1, gbc_lblNewLabel_1); + + comboZone = new ComboBox(ZONE_LABEL); + comboZone.setEnabled(false); + GridBagConstraints gbc_comboZone = new GridBagConstraints(); + gbc_comboZone.insets = new Insets(0, 0, 5, 0); + gbc_comboZone.fill = GridBagConstraints.HORIZONTAL; + gbc_comboZone.gridx = 1; + gbc_comboZone.gridy = 2; + add(comboZone, gbc_comboZone); + + JLabel lblNewLabel_2 = new JLabel("AccessKey*"); + GridBagConstraints gbc_lblNewLabel_2 = new GridBagConstraints(); + gbc_lblNewLabel_2.anchor = GridBagConstraints.EAST; + gbc_lblNewLabel_2.insets = new Insets(0, 0, 5, 5); + gbc_lblNewLabel_2.gridx = 0; + gbc_lblNewLabel_2.gridy = 3; + add(lblNewLabel_2, gbc_lblNewLabel_2); + + textAccessKey = new JTextField(); + GridBagConstraints gbc_textAccessKey = new GridBagConstraints(); + gbc_textAccessKey.insets = new Insets(0, 0, 5, 0); + gbc_textAccessKey.fill = GridBagConstraints.HORIZONTAL; + gbc_textAccessKey.gridx = 1; + gbc_textAccessKey.gridy = 3; + add(textAccessKey, gbc_textAccessKey); + textAccessKey.setColumns(10); + + JLabel lblNewLabel_3 = new JLabel("SecretKey*"); + GridBagConstraints gbc_lblNewLabel_3 = new GridBagConstraints(); + gbc_lblNewLabel_3.anchor = GridBagConstraints.EAST; + gbc_lblNewLabel_3.insets = new Insets(0, 0, 5, 5); + gbc_lblNewLabel_3.gridx = 0; + gbc_lblNewLabel_3.gridy = 4; + add(lblNewLabel_3, gbc_lblNewLabel_3); + + textSecretKey = new JTextField(); + GridBagConstraints gbc_textSecretKey = new GridBagConstraints(); + gbc_textSecretKey.insets = new Insets(0, 0, 5, 0); + gbc_textSecretKey.fill = GridBagConstraints.HORIZONTAL; + gbc_textSecretKey.gridx = 1; + gbc_textSecretKey.gridy = 4; + add(textSecretKey, gbc_textSecretKey); + textSecretKey.setColumns(10); + + JLabel lblNewLabel_4 = new JLabel("存储空间"); + GridBagConstraints gbc_lblNewLabel_4 = new GridBagConstraints(); + gbc_lblNewLabel_4.anchor = GridBagConstraints.EAST; + gbc_lblNewLabel_4.insets = new Insets(0, 0, 5, 5); + gbc_lblNewLabel_4.gridx = 0; + gbc_lblNewLabel_4.gridy = 5; + add(lblNewLabel_4, gbc_lblNewLabel_4); + + textBucket = new JTextField(); + GridBagConstraints gbc_textZone = new GridBagConstraints(); + gbc_textZone.insets = new Insets(0, 0, 5, 0); + gbc_textZone.fill = GridBagConstraints.HORIZONTAL; + gbc_textZone.gridx = 1; + gbc_textZone.gridy = 5; + add(textBucket, gbc_textZone); + textBucket.setColumns(10); + + JLabel lblNewLabel_5 = new JLabel("空间域名"); + GridBagConstraints gbc_lblNewLabel_5 = new GridBagConstraints(); + gbc_lblNewLabel_5.anchor = GridBagConstraints.EAST; + gbc_lblNewLabel_5.insets = new Insets(0, 0, 5, 5); + gbc_lblNewLabel_5.gridx = 0; + gbc_lblNewLabel_5.gridy = 6; + add(lblNewLabel_5, gbc_lblNewLabel_5); + + textDomain = new JTextField(); + GridBagConstraints gbc_textDomain = new GridBagConstraints(); + gbc_textDomain.insets = new Insets(0, 0, 5, 0); + gbc_textDomain.fill = GridBagConstraints.HORIZONTAL; + gbc_textDomain.gridx = 1; + gbc_textDomain.gridy = 6; + add(textDomain, gbc_textDomain); + textDomain.setColumns(10); + + chkTs = new JCheckBox("给上传的文件添加时间戳(下载时强制更新缓存)"); + GridBagConstraints gbc_chkTs = new GridBagConstraints(); + gbc_chkTs.anchor = GridBagConstraints.WEST; + gbc_chkTs.gridwidth = 2; + gbc_chkTs.gridx = 0; + gbc_chkTs.gridy = 7; + add(chkTs, gbc_chkTs); + } + + public boolean isModified() { + return settings.getState().QN_ZONE != comboZone.getSelectedIndex() + || settings.getState().QN_ENABLE != chkEnable.isSelected() + || settings.getState().QN_TS != chkTs.isSelected() + || !settings.getState().QN_AK.equals(textAccessKey.getText().trim()) + || !settings.getState().QN_SK.equals(textSecretKey.getText().trim()) + || !settings.getState().QN_BUCKET.equals(textBucket.getText().trim()) + || !settings.getState().QN_DOMAIN.equals(textDomain.getText().trim()) + ; + } + + public void reset() { + int idx = settings.getState().QN_ZONE; + if (idx >= 0 && idx < comboZone.getItemCount()) { + comboZone.setSelectedIndex(idx); + } + chkEnable.setSelected(settings.getState().QN_ENABLE); + chkTs.setSelected(settings.getState().QN_TS); + textAccessKey.setText(settings.getState().QN_AK); + textSecretKey.setText(settings.getState().QN_SK); + textBucket.setText(settings.getState().QN_BUCKET); + textDomain.setText(settings.getState().QN_DOMAIN); + } + + public void apply() { + settings.getState().QN_ZONE = comboZone.getSelectedIndex(); + settings.getState().QN_ENABLE = chkEnable.isSelected(); + settings.getState().QN_TS = chkTs.isSelected(); + settings.getState().QN_AK = textAccessKey.getText().trim(); + settings.getState().QN_SK = textSecretKey.getText().trim(); + settings.getState().QN_BUCKET = textBucket.getText().trim(); + settings.getState().QN_DOMAIN = textDomain.getText().trim(); + } +} diff --git a/src/cn/ieclipse/smartim/views/CheckBoxTreeCellRenderer.java b/src/cn/ieclipse/smartim/views/CheckBoxTreeCellRenderer.java new file mode 100644 index 0000000..562a666 --- /dev/null +++ b/src/cn/ieclipse/smartim/views/CheckBoxTreeCellRenderer.java @@ -0,0 +1,79 @@ +package cn.ieclipse.smartim.views; + +import javax.swing.*; +import javax.swing.plaf.ColorUIResource; +import javax.swing.tree.TreeCellRenderer; +import java.awt.*; + +public class CheckBoxTreeCellRenderer extends JPanel + implements TreeCellRenderer { + protected JCheckBox check; + protected CheckBoxTreeLabel label; + + public CheckBoxTreeCellRenderer() { + setLayout(null); + add(check = new JCheckBox()); + add(label = new CheckBoxTreeLabel()); + check.setBackground(UIManager.getColor("Tree.textBackground")); + label.setForeground(UIManager.getColor("Tree.textForeground")); + } + + /** + * 返回的是一个JPanel对象,该对象中包含一个JCheckBox对象 和一个 + * JLabel对象。并且根据每个结点是否被选中来决定JCheckBox 是否被选中。 + */ + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, + boolean selected, boolean expanded, boolean leaf, int row, + boolean hasFocus) { + String stringValue = tree.convertValueToText(value, selected, expanded, + leaf, row, hasFocus); + setEnabled(tree.isEnabled()); + if (value instanceof CheckBoxTreeNode) { + check.setSelected(((CheckBoxTreeNode) value).isSelected()); + } + label.setFont(tree.getFont()); + label.setText(stringValue); + label.setSelected(selected); + label.setFocus(hasFocus); + if (leaf) + label.setIcon(UIManager.getIcon("Tree.leafIcon")); + else if (expanded) + label.setIcon(UIManager.getIcon("Tree.openIcon")); + else + label.setIcon(UIManager.getIcon("Tree.closedIcon")); + + return this; + } + + @Override + public Dimension getPreferredSize() { + Dimension dCheck = check.getPreferredSize(); + Dimension dLabel = label.getPreferredSize(); + return new Dimension(dCheck.width + dLabel.width, + dCheck.height < dLabel.height ? dLabel.height : dCheck.height); + } + + @Override + public void doLayout() { + Dimension dCheck = check.getPreferredSize(); + Dimension dLabel = label.getPreferredSize(); + int yCheck = 0; + int yLabel = 0; + if (dCheck.height < dLabel.height) + yCheck = (dLabel.height - dCheck.height) / 2; + else + yLabel = (dCheck.height - dLabel.height) / 2; + check.setLocation(0, yCheck); + check.setBounds(0, yCheck, dCheck.width, dCheck.height); + label.setLocation(dCheck.width, yLabel); + label.setBounds(dCheck.width, yLabel, dLabel.width, dLabel.height); + } + + @Override + public void setBackground(Color color) { + if (color instanceof ColorUIResource) + color = null; + super.setBackground(color); + } +} \ No newline at end of file diff --git a/src/cn/ieclipse/smartim/views/CheckBoxTreeLabel.java b/src/cn/ieclipse/smartim/views/CheckBoxTreeLabel.java new file mode 100644 index 0000000..fb7bfde --- /dev/null +++ b/src/cn/ieclipse/smartim/views/CheckBoxTreeLabel.java @@ -0,0 +1,63 @@ +package cn.ieclipse.smartim.views; + +import javax.swing.*; +import javax.swing.plaf.ColorUIResource; +import java.awt.*; + +public class CheckBoxTreeLabel extends JLabel { + private boolean isSelected; + private boolean hasFocus; + + public CheckBoxTreeLabel() { + } + + @Override + public void setBackground(Color color) { + if (color instanceof ColorUIResource) + color = null; + super.setBackground(color); + } + + @Override + public void paint(Graphics g) { + String str; + if ((str = getText()) != null) { + if (0 < str.length()) { + if (isSelected) + g.setColor(UIManager.getColor("Tree.selectionBackground")); + else + g.setColor(UIManager.getColor("Tree.textBackground")); + Dimension d = getPreferredSize(); + int imageOffset = 0; + Icon currentIcon = getIcon(); + if (currentIcon != null) + imageOffset = currentIcon.getIconWidth() + + Math.max(0, getIconTextGap() - 1); + g.fillRect(imageOffset, 0, d.width - 1 - imageOffset, d.height); + if (hasFocus) { + g.setColor(UIManager.getColor("Tree.selectionBorderColor")); + g.drawRect(imageOffset, 0, d.width - 1 - imageOffset, + d.height - 1); + } + } + } + super.paint(g); + } + + @Override + public Dimension getPreferredSize() { + Dimension retDimension = super.getPreferredSize(); + if (retDimension != null) + retDimension = new Dimension(retDimension.width + 3, + retDimension.height); + return retDimension; + } + + public void setSelected(boolean isSelected) { + this.isSelected = isSelected; + } + + public void setFocus(boolean hasFocus) { + this.hasFocus = hasFocus; + } +} \ No newline at end of file diff --git a/src/cn/ieclipse/smartim/views/CheckBoxTreeNode.java b/src/cn/ieclipse/smartim/views/CheckBoxTreeNode.java new file mode 100644 index 0000000..f113923 --- /dev/null +++ b/src/cn/ieclipse/smartim/views/CheckBoxTreeNode.java @@ -0,0 +1,89 @@ +package cn.ieclipse.smartim.views; + +import javax.swing.tree.DefaultMutableTreeNode; + +public class CheckBoxTreeNode extends DefaultMutableTreeNode { + protected boolean isSelected; + + public CheckBoxTreeNode() { + this(null); + } + + public CheckBoxTreeNode(Object userObject) { + this(userObject, true, false); + } + + public CheckBoxTreeNode(Object userObject, boolean allowsChildren, + boolean isSelected) { + super(userObject, allowsChildren); + this.isSelected = isSelected; + } + + public boolean isSelected() { + return isSelected; + } + + public void setSelected(boolean _isSelected) { + this.isSelected = _isSelected; + + if (_isSelected) { + // 如果选中,则将其所有的子结点都选中 + if (children != null) { + for (Object obj : children) { + CheckBoxTreeNode node = (CheckBoxTreeNode) obj; + if (_isSelected != node.isSelected()) + node.setSelected(_isSelected); + } + } + // 向上检查,如果父结点的所有子结点都被选中,那么将父结点也选中 + CheckBoxTreeNode pNode = (CheckBoxTreeNode) parent; + // 开始检查pNode的所有子节点是否都被选中 + if (pNode != null) { + int index = 0; + for (; index < pNode.children.size(); ++index) { + CheckBoxTreeNode pChildNode = (CheckBoxTreeNode) pNode.children + .get(index); + if (!pChildNode.isSelected()) + break; + } + /* + * 表明pNode所有子结点都已经选中,则选中父结点, 该方法是一个递归方法,因此在此不需要进行迭代,因为 + * 当选中父结点后,父结点本身会向上检查的。 + */ + if (index == pNode.children.size()) { + if (pNode.isSelected() != _isSelected) + pNode.setSelected(_isSelected); + } + } + } + else { + /* + * 如果是取消父结点导致子结点取消,那么此时所有的子结点都应该是选择上的; + * 否则就是子结点取消导致父结点取消,然后父结点取消导致需要取消子结点,但 是这时候是不需要取消子结点的。 + */ + if (children != null) { + int index = 0; + for (; index < children.size(); ++index) { + CheckBoxTreeNode childNode = (CheckBoxTreeNode) children + .get(index); + if (!childNode.isSelected()) + break; + } + // 从上向下取消的时候 + if (index == children.size()) { + for (int i = 0; i < children.size(); ++i) { + CheckBoxTreeNode node = (CheckBoxTreeNode) children + .get(i); + if (node.isSelected() != _isSelected) + node.setSelected(_isSelected); + } + } + } + + // 向上取消,只要存在一个子节点不是选上的,那么父节点就不应该被选上。 + CheckBoxTreeNode pNode = (CheckBoxTreeNode) parent; + if (pNode != null && pNode.isSelected() != _isSelected) + pNode.setSelected(_isSelected); + } + } +} diff --git a/src/cn/ieclipse/smartim/views/CheckBoxTreeNodeSelectionListener.java b/src/cn/ieclipse/smartim/views/CheckBoxTreeNodeSelectionListener.java new file mode 100644 index 0000000..e3598e4 --- /dev/null +++ b/src/cn/ieclipse/smartim/views/CheckBoxTreeNodeSelectionListener.java @@ -0,0 +1,43 @@ +package cn.ieclipse.smartim.views; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreePath; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class CheckBoxTreeNodeSelectionListener extends MouseAdapter { + @Override + public void mouseClicked(MouseEvent event) { + JTree tree = (JTree) event.getSource(); + int x = event.getX(); + int y = event.getY(); + int row = tree.getRowForLocation(x, y); + TreePath path = tree.getPathForRow(row); + if (path != null) { + DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path + .getLastPathComponent(); + if (selectedNode != null && selectedNode.getChildCount() > 0 + && event.getClickCount() > 1) { + // if (tree.isExpanded(path)) { + // tree.collapsePath(path); + // } + // else { + // tree.expandPath(path); + // } + return; + } + else if (selectedNode instanceof CheckBoxTreeNode + && event.getClickCount() == 1) { + CheckBoxTreeNode node = (CheckBoxTreeNode) selectedNode; + if (node != null) { + boolean isSelected = !node.isSelected(); + node.setSelected(isSelected); + ((DefaultTreeModel) tree.getModel()) + .nodeStructureChanged(node); + } + } + } + } +} \ No newline at end of file diff --git a/src/cn/ieclipse/smartim/views/ContactTreeCellRenderer.java b/src/cn/ieclipse/smartim/views/ContactTreeCellRenderer.java index 99d140a..b54d2ac 100644 --- a/src/cn/ieclipse/smartim/views/ContactTreeCellRenderer.java +++ b/src/cn/ieclipse/smartim/views/ContactTreeCellRenderer.java @@ -3,7 +3,6 @@ import cn.ieclipse.smartim.model.IContact; import com.intellij.ui.ColoredTreeCellRenderer; import com.scienjus.smartqq.model.Discuss; -import com.scienjus.smartqq.model.Friend; import com.scienjus.smartqq.model.Group; import com.scienjus.smartqq.model.Recent; import icons.SmartIcons; diff --git a/src/cn/ieclipse/smartim/views/ContactTreeNode.java b/src/cn/ieclipse/smartim/views/ContactTreeNode.java index aaebfb2..4f9deff 100644 --- a/src/cn/ieclipse/smartim/views/ContactTreeNode.java +++ b/src/cn/ieclipse/smartim/views/ContactTreeNode.java @@ -1,19 +1,19 @@ package cn.ieclipse.smartim.views; -import javax.swing.tree.DefaultMutableTreeNode; - /** * Created by Jamling on 2017/7/12. */ -public abstract class ContactTreeNode extends DefaultMutableTreeNode { - protected boolean check; +public abstract class ContactTreeNode extends CheckBoxTreeNode { protected String name; protected IMPanel imPanel; + public ContactTreeNode(Object userObject) { + super(userObject); + } + public ContactTreeNode(boolean check, String name, IMPanel imPanel) { - super(new DefaultMutableTreeNode(name)); + super(new CheckBoxTreeNode(name)); this.name = name; - this.check = check; this.imPanel = imPanel; } diff --git a/src/cn/ieclipse/smartim/views/IMContactDoubleClicker.java b/src/cn/ieclipse/smartim/views/IMContactDoubleClicker.java index 12f0369..e4bee4e 100644 --- a/src/cn/ieclipse/smartim/views/IMContactDoubleClicker.java +++ b/src/cn/ieclipse/smartim/views/IMContactDoubleClicker.java @@ -25,7 +25,7 @@ public void mouseClicked(MouseEvent e) { if (selRow != -1 && selPath != null) { DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) selPath .getLastPathComponent(); - if (selectedNode.getChildCount() > 1) { + if (selectedNode.getChildCount() > 0) { if (tree.isExpanded(selPath)) { tree.collapsePath(selPath); } diff --git a/src/cn/ieclipse/smartim/views/IMPanel.java b/src/cn/ieclipse/smartim/views/IMPanel.java index c2f6791..3a4faf0 100644 --- a/src/cn/ieclipse/smartim/views/IMPanel.java +++ b/src/cn/ieclipse/smartim/views/IMPanel.java @@ -6,10 +6,9 @@ import cn.ieclipse.smartim.console.ClosableTabHost; import cn.ieclipse.smartim.console.IMChatConsole; import cn.ieclipse.smartim.model.IContact; -import cn.ieclipse.smartim.settings.SmartSettingsPanel; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.options.ShowSettingsUtil; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.ActionToolbar; +import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.SimpleToolWindowPanel; import com.intellij.openapi.wm.ToolWindow; @@ -57,11 +56,12 @@ public Project getProject() { private void initUI() { DefaultActionGroup group = new DefaultActionGroup(); - group.add(new LoginAction(this, toolWindow)); + group.add(new LoginAction(this)); group.add(new HideContactAction(this)); group.add(new DisconnectAction(this)); + createBroadcastAction(group); group.add(new SettingAction(this)); - // group.add(new TestAction(this)); + //group.add(new MockConsoleAction(this)); ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar("SmartQQ", group, false); // toolbar.getComponent().addFocusListener(createFocusListener()); @@ -97,6 +97,8 @@ public void setLeftHide(boolean select) { public abstract IMChatConsole createConsoleUI(IContact contact); + public abstract BroadcastAction createBroadcastAction(DefaultActionGroup group); + private Map consoles = new HashMap<>(); public Map getConsoles() { diff --git a/src/cn/ieclipse/smartqq/QQBroadcastAction.java b/src/cn/ieclipse/smartqq/QQBroadcastAction.java new file mode 100644 index 0000000..8e5780b --- /dev/null +++ b/src/cn/ieclipse/smartqq/QQBroadcastAction.java @@ -0,0 +1,19 @@ +package cn.ieclipse.smartqq; + +import cn.ieclipse.smartim.actions.BroadcastAction; + +import javax.swing.*; + +public class QQBroadcastAction extends BroadcastAction { + + public QQBroadcastAction(SmartQQPanel panel) { + super(panel); + } + + @Override + protected void openDialog() { + QQBroadcastDialog dialog = new QQBroadcastDialog((SmartQQPanel) imPanel); + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } +} diff --git a/src/cn/ieclipse/smartqq/QQBroadcastDialog.java b/src/cn/ieclipse/smartqq/QQBroadcastDialog.java new file mode 100644 index 0000000..bc4b1e0 --- /dev/null +++ b/src/cn/ieclipse/smartqq/QQBroadcastDialog.java @@ -0,0 +1,109 @@ +package cn.ieclipse.smartqq; + +import cn.ieclipse.smartim.actions.BroadcastAction; +import cn.ieclipse.smartim.dialogs.BroadcastDialog; +import cn.ieclipse.smartim.model.IContact; +import cn.ieclipse.smartim.model.IMessage; +import cn.ieclipse.smartim.views.ContactTreeMode; +import cn.ieclipse.smartim.views.IMPanel; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.treeStructure.Tree; +import com.scienjus.smartqq.client.SmartQQClient; +import com.scienjus.smartqq.model.Discuss; +import com.scienjus.smartqq.model.Friend; +import com.scienjus.smartqq.model.Group; + +import javax.swing.*; +import java.util.List; + +public class QQBroadcastDialog extends BroadcastDialog { + private JTree recentTree; + private JTree friendTree; + private JTree groupTree; + private JTree discussTree; + private QQContactTreeNode root1, root2, root3, root4; + private ContactTreeMode recentModel; + private ContactTreeMode friendModel; + private ContactTreeMode groupModel; + private ContactTreeMode discussModel; + + public QQBroadcastDialog(IMPanel panel) { + super(panel); + } + + @Override + protected void initTab(JTabbedPane host) { + // recentTree = new JTree(); + friendTree = new Tree(); + groupTree = new Tree(); + discussTree = new Tree(); + + // JScrollPane scrollPane1 = new JScrollPane(recentTree); + // tabHost.addTab("最近", null, scrollPane1, null); + + JScrollPane scrollPane2 = new JBScrollPane(friendTree); + tabHost.addTab("好友", null, scrollPane2, null); + + JScrollPane scrollPane3 = new JBScrollPane(groupTree); + tabHost.addTab("群组", null, scrollPane3, null); + + JScrollPane scrollPane4 = new JBScrollPane(discussTree); + tabHost.addTab("讨论组", null, scrollPane4, null); + + initTrees(recentTree, friendTree, groupTree, discussTree); + // root1 = new QQContactTreeNode(false, "recent", imPanel); + root2 = new QQContactTreeNode(false, "friend", imPanel); + root3 = new QQContactTreeNode(false, "group", imPanel); + root4 = new QQContactTreeNode(false, "discuss", imPanel); + root2.update(); + root3.update(); + root4.update(); + + // recentModel = new ContactTreeMode(root1); + friendModel = new ContactTreeMode(root2); + groupModel = new ContactTreeMode(root3); + discussModel = new ContactTreeMode(root4); + + // recentTree.setModel(recentModel); + friendTree.setModel(friendModel); + groupTree.setModel(groupModel); + discussTree.setModel(discussModel); + + + } + + protected void sendInternal(String text, List targets) { + SmartQQClient client = (SmartQQClient) imPanel.getClient(); + int ret = 0; + if (targets != null) { + for (Object obj : targets) { + if (obj != null && obj instanceof IContact) { + IContact target = (IContact) obj; + try { + IMessage m = createMessage(text, target, client); + client.sendMessage(m, target); + ret++; + } catch (Exception e) { + + } + } + } + } + } + + protected IMessage createMessage(String text, IContact target, + SmartQQClient client) { + IMessage m = null; + if (!client.isClose()) { + if (target instanceof Friend) { + m = client.createMessage(text, target); + } + else if (target instanceof Group || target instanceof Discuss) { + String msg = text.replace(BroadcastAction.groupMacro, + target.getName()); + m = client.createMessage(msg, target); + } + } + return m; + } +} diff --git a/src/cn/ieclipse/smartqq/QQChatConsole.java b/src/cn/ieclipse/smartqq/QQChatConsole.java index 5b2fb73..64b6704 100644 --- a/src/cn/ieclipse/smartqq/QQChatConsole.java +++ b/src/cn/ieclipse/smartqq/QQChatConsole.java @@ -15,7 +15,6 @@ import com.scienjus.smartqq.model.Friend; import com.scienjus.smartqq.model.QQMessage; -import javax.swing.*; import java.io.File; /** @@ -27,37 +26,6 @@ public QQChatConsole(IContact target, SmartQQPanel imPanel) { super(target, imPanel); } - public void sendFileInternal(final String file) throws Exception { - final File f = new File(file); - QNUploader uploader = new QNUploader(); - String ak = ""; - String sk = ""; - String bucket = ""; - String domain = ""; - String qq = getClient() - .getAccount().getAccount(); - boolean enable = false; - boolean ts = false; - if (!enable) { - ak = ""; - sk = ""; - } - QNUploader.UploadInfo info = uploader.upload(qq, f, ak, sk, bucket, - null); - String url = info.getUrl(domain, ts); - - String msg = String.format( - "来自SmartQQ的文件: %s (大小%s), 点击链接 %s 查看", - IMUtils.getName(file), - IMUtils.formatFileSize(info.fsize), url); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - send(msg); - } - }); - } - @Override public SmartQQClient getClient() { return (SmartQQClient) super.getClient(); @@ -98,14 +66,6 @@ private void createUIComponents() { } - public void write(String msg) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - insertDocument(msg); - } - }); - } @Override public boolean hideMyInput() { @@ -114,4 +74,31 @@ public boolean hideMyInput() { } return SmartIMSettings.getInstance().getState().HIDE_MY_INPUT; } + + @Override + protected void sendFileInternal(String file) throws Exception { + final File f = new File(file); + if (f.length() > (1 << 18)) { + write(String.format("%s 上传中,请稍候……", f.getName())); + } + QNUploader uploader = new QNUploader(); + String ak = SmartIMSettings.getInstance().getState().QN_AK; + String sk = SmartIMSettings.getInstance().getState().QN_SK; + String bucket = SmartIMSettings.getInstance().getState().QN_BUCKET; + String domain = SmartIMSettings.getInstance().getState().QN_DOMAIN; + String qq = getClient().getAccount().getAccount(); + boolean enable = SmartIMSettings.getInstance().getState().QN_ENABLE; + boolean ts = SmartIMSettings.getInstance().getState().QN_TS; + if (!enable) { + ak = ""; + sk = ""; + } + QNUploader.UploadInfo info = uploader.upload(qq, f, ak, sk, bucket, + null); + String url = info.getUrl(domain, ts); + + final String msg = String.format("来自SmartQQ的文件: %s (大小%s), 点击链接 %s 查看", + IMUtils.getName(file), IMUtils.formatFileSize(info.fsize), url); + send(msg); + } } diff --git a/src/cn/ieclipse/smartqq/QQContactTreeNode.java b/src/cn/ieclipse/smartqq/QQContactTreeNode.java index 04141f9..3539b8b 100644 --- a/src/cn/ieclipse/smartqq/QQContactTreeNode.java +++ b/src/cn/ieclipse/smartqq/QQContactTreeNode.java @@ -5,7 +5,6 @@ import com.scienjus.smartqq.client.SmartQQClient; import com.scienjus.smartqq.model.*; -import javax.swing.tree.DefaultMutableTreeNode; import java.util.Collections; import java.util.List; @@ -14,13 +13,17 @@ */ public class QQContactTreeNode extends ContactTreeNode { + public QQContactTreeNode(Object userObject) { + super(userObject); + } + public QQContactTreeNode(boolean check, String name, IMPanel imPanel) { super(check, name, imPanel); } public void update() { SmartQQClient client = (SmartQQClient) imPanel.getClient(); - DefaultMutableTreeNode root = (DefaultMutableTreeNode) getRoot(); + QQContactTreeNode root = (QQContactTreeNode) getRoot(); root.removeAllChildren(); if ("recent".equals(name)) { List list = client.getRecents2(); @@ -29,7 +32,7 @@ public void update() { Collections.sort(list); } for (QQContact target : list) { - DefaultMutableTreeNode cn = new DefaultMutableTreeNode(target); + QQContactTreeNode cn = new QQContactTreeNode(target); root.add(cn); } } @@ -37,10 +40,10 @@ public void update() { List categories = client.getFriendListWithCategory(); if (categories != null) { for (Category c : categories) { - DefaultMutableTreeNode cn = new DefaultMutableTreeNode(c); + QQContactTreeNode cn = new QQContactTreeNode(c); root.add(cn); for (Friend f : c.getFriends()) { - DefaultMutableTreeNode fn = new DefaultMutableTreeNode(f); + QQContactTreeNode fn = new QQContactTreeNode(f); cn.add(fn); } } @@ -49,7 +52,7 @@ public void update() { List list = client.getGroupList(); if (list != null) { for (Group r : list) { - DefaultMutableTreeNode cn = new DefaultMutableTreeNode(r); + QQContactTreeNode cn = new QQContactTreeNode(r); root.add(cn); } } @@ -57,7 +60,7 @@ public void update() { List list = client.getDiscussList(); if (list != null) { for (Discuss r : list) { - DefaultMutableTreeNode cn = new DefaultMutableTreeNode(r); + QQContactTreeNode cn = new QQContactTreeNode(r); root.add(cn); } } diff --git a/src/cn/ieclipse/smartqq/QQContactView.java b/src/cn/ieclipse/smartqq/QQContactView.java index 21f919e..78a5b4f 100644 --- a/src/cn/ieclipse/smartqq/QQContactView.java +++ b/src/cn/ieclipse/smartqq/QQContactView.java @@ -1,9 +1,7 @@ package cn.ieclipse.smartqq; -import cn.ieclipse.smartim.IMClientFactory; import cn.ieclipse.smartim.IMSendCallback; import cn.ieclipse.smartim.common.LOG; -import cn.ieclipse.smartim.views.ContactTabHost; import cn.ieclipse.smartim.views.ContactTreeMode; import cn.ieclipse.smartim.views.IMContactView; import com.intellij.ui.components.JBTabbedPane; @@ -11,9 +9,6 @@ import com.scienjus.smartqq.client.SmartQQClient; import javax.swing.*; -import javax.swing.plaf.TabbedPaneUI; -import javax.swing.plaf.basic.BasicTabbedPaneUI; -import java.awt.*; /** * Created by Jamling on 2017/7/11. @@ -42,7 +37,7 @@ public QQContactView(SmartQQPanel imPanel) { receiveCallback = new QQReceiveCallback(imPanel); sendCallback = new IMSendCallback(imPanel); - robotCallback = null; + robotCallback = new QQRobotCallback(imPanel); modificationCallback = new QQModificationCallback(imPanel); root1 = new QQContactTreeNode(false, "recent", imPanel); @@ -76,11 +71,6 @@ public void init() { discussTree.setModel(discussModel); } - @Override - protected void initTree(Tree tree) { - super.initTree(tree); - } - @Override protected SmartQQClient getClient() { return getImPanel().getClient(); diff --git a/src/cn/ieclipse/smartqq/QQReceiveCallback.java b/src/cn/ieclipse/smartqq/QQReceiveCallback.java index 8bc62a8..318b733 100644 --- a/src/cn/ieclipse/smartqq/QQReceiveCallback.java +++ b/src/cn/ieclipse/smartqq/QQReceiveCallback.java @@ -15,25 +15,18 @@ */ package cn.ieclipse.smartqq; -import com.scienjus.smartqq.client.SmartQQClient; -import com.scienjus.smartqq.model.DiscussFrom; -import com.scienjus.smartqq.model.FriendFrom; -import com.scienjus.smartqq.model.GroupFrom; -import com.scienjus.smartqq.model.QQContact; -import com.scienjus.smartqq.model.QQMessage; - -import cn.ieclipse.smartim.IMClientFactory; -import cn.ieclipse.smartim.IMHistoryManager; import cn.ieclipse.smartim.IMReceiveCallback; import cn.ieclipse.smartim.common.IMUtils; -import cn.ieclipse.smartim.common.LOG; -import cn.ieclipse.smartim.common.Notifications; import cn.ieclipse.smartim.model.IContact; import cn.ieclipse.smartim.model.impl.AbstractContact; import cn.ieclipse.smartim.model.impl.AbstractFrom; import cn.ieclipse.smartim.model.impl.AbstractMessage; import cn.ieclipse.smartim.settings.SmartIMSettings; -import cn.ieclipse.smartim.views.IMPanel; +import com.scienjus.smartqq.client.SmartQQClient; +import com.scienjus.smartqq.model.DiscussFrom; +import com.scienjus.smartqq.model.FriendFrom; +import com.scienjus.smartqq.model.GroupFrom; +import com.scienjus.smartqq.model.QQMessage; /** * 类/接口描述 @@ -85,6 +78,7 @@ protected String getMsgContent(AbstractMessage message, AbstractFrom from) { if (message instanceof QQMessage) { QQMessage m = (QQMessage) message; msg = IMUtils.formatHtmlMsg(m.getTime(), name, m.getContent()); + msg = QQUtils.decodeEmoji(msg); } return msg; } diff --git a/src/cn/ieclipse/smartqq/QQRobotCallback.java b/src/cn/ieclipse/smartqq/QQRobotCallback.java new file mode 100644 index 0000000..001600c --- /dev/null +++ b/src/cn/ieclipse/smartqq/QQRobotCallback.java @@ -0,0 +1,244 @@ +package cn.ieclipse.smartqq; + +import cn.ieclipse.smartim.IMRobotCallback; +import cn.ieclipse.smartim.common.LOG; +import cn.ieclipse.smartim.model.IContact; +import cn.ieclipse.smartim.model.IFrom; +import cn.ieclipse.smartim.model.impl.AbstractFrom; +import cn.ieclipse.smartim.model.impl.AbstractMessage; +import cn.ieclipse.smartim.robot.TuringRobot.TuringRequestV2Builder; +import cn.ieclipse.smartim.settings.SmartIMSettings; +import cn.ieclipse.util.StringUtils; +import com.scienjus.smartqq.client.SmartQQClient; +import com.scienjus.smartqq.model.*; + +import java.util.Map; + +public class QQRobotCallback extends IMRobotCallback { + + private QQChatConsole console; + private SmartQQPanel fContactView; + + public QQRobotCallback(SmartQQPanel fContactView) { + this.fContactView = fContactView; + } + + @Override + public void onContactChanged(IContact contact) { + if (!isEnable()) { + return; + } + try { + console = (QQChatConsole) fContactView + .findConsoleById(contact.getUin(), false); + // TODO + } catch (Exception e) { + LOG.error("机器人回应异常", e); + } + } + + @Override + public void onReceiveMessage(AbstractMessage message, AbstractFrom from) { + if (!isEnable()) { + return; + } + try { + console = (QQChatConsole) fContactView + .findConsoleById(from.getContact().getUin(), false); + answer(from, (QQMessage) message); + } catch (Exception e) { + LOG.error("机器人回应异常", e); + } + } + + @Override + public void onReceiveError(Throwable e) { + // TODO Auto-generated method stub + + } + + public void answer(AbstractFrom from, QQMessage m) { + String robotName = getRobotName(); + SmartQQClient client = fContactView.getClient(); + // auto reply friend + if (from instanceof FriendFrom) { + if (SmartIMSettings.getInstance().getState().ROBOT_FRIEND_ANY) { + String reply = getReply(m.getContent(), + (QQContact) from.getContact(), null); + if (reply != null) { + String input = robotName + reply; + if (console == null) { + client.sendMessageToFriend(m.getUserId(), input); + } + else { + console.send(input); + } + } + } + return; + } + else if (from instanceof GroupFrom) { + GroupFrom gf = (GroupFrom) from; + String gName = gf.getGroup().getName(); + // QQContact qqContact = client.getGroup(gf.getGroup().getId()); + if (from.isNewbie()) { + String welcome = SmartIMSettings.getInstance() + .getState().ROBOT_GROUP_WELCOME; + if (welcome != null && !welcome.isEmpty()) { + GroupInfo info = gf.getGroup(); + GroupUser gu = gf.getGroupUser(); + String input = welcome; + if (gu != null) { + input = input.replace("{user}", gu.getName()); + } + if (info != null) { + input = input.replace("{memo}", info.getMemo()); + } + if (console != null) { + console.send(robotName + input); + } + else { + client.sendMessageToGroup(gf.getGroup().getId(), + robotName + input); + } + } + } + + // @ + if (atMe(from, m)) { + String msg = m.getContent(true).trim(); + String reply = getReply(msg, from.getMember(), gName); + if (reply != null) { + String input = robotName + "@" + from.getMember().getName() + + SEP + reply; + if (console != null) { + console.send(input); + } + else { + if (m instanceof GroupMessage) { + client.sendMessageToGroup( + ((GroupMessage) m).getGroupId(), input); + } + else if (m instanceof DiscussMessage) { + client.sendMessageToDiscuss( + ((DiscussMessage) m).getDiscussId(), input); + } + } + } + return; + } + // replay any + if (SmartIMSettings.getInstance().getState().ROBOT_GROUP_ANY) { + if (from.isNewbie() || isMySend(m.getUserId())) { + return; + } + if (console == null) { + return; + } + + if (from instanceof FriendFrom) { + return; + } + else if (from instanceof GroupFrom) { + if (((GroupFrom) from).getGroupUser().isUnknown()) { + return; + } + } + else if (from instanceof DiscussFrom) { + if (((DiscussFrom) from).getDiscussUser().isUnknown()) { + return; + } + } + + String reply = getReply(m.getContent(), from.getMember(), + gName); + if (reply != null) { + String input = robotName + "@" + from.getName() + SEP + + reply; + if (console != null) { + console.send(input); + } + } + } + } // end group + + } + + private Map getParams(String text, IContact contact, + String groupId) { + String key = getTuringApiKey(); + if (StringUtils.isEmpty(key)) { + return null; + } + TuringRequestV2Builder builder = new TuringRequestV2Builder(key); + builder.setText(text); + String uid = encodeUid(contact.getName()); + String uname = contact.getName(); + String gid = groupId == null ? null : encodeUid(groupId); + builder.setUserInfo(uid, uname, gid); + // builder.setLocation(contact, contact.Province, null); + return builder.build(); + } + + private String getReply(String text, IContact contact, String groupId) { + if (StringUtils.isEmpty(text)) { + String reply = SmartIMSettings.getInstance() + .getState().ROBOT_REPLY_EMPTY; + if (!StringUtils.isEmpty(reply)) { + return reply; + } + return null; + } + Map params = getParams(text, contact, groupId); + if (params != null) { + try { + return turingRobot.getRobotAnswer(text, params); + } catch (Exception e) { + LOG.error("机器人回复失败", e); + } + } + return null; + } + + private boolean atMe(IFrom from, QQMessage m) { + if (m.getAts() != null) { + if (m instanceof GroupMessage) { + GroupInfo info = ((GroupFrom) from).getGroup(); + UserInfo me = getAccount(); + long uin = Long.parseLong(me.getUin()); + GroupUser me2 = info.getGroupUser(uin); + if (m.hasAt(me2.getName()) || m.hasAt(me.getNick())) { + return true; + } + } + + else if (m instanceof DiscussMessage) { + DiscussInfo info = ((DiscussFrom) from).getDiscuss(); + UserInfo me = getAccount(); + long uin = Long.parseLong(me.getUin()); + DiscussUser me2 = info.getDiscussUser(uin); + if (m.hasAt(me2.getName()) || m.hasAt(me.getNick())) { + return true; + } + } + } + return false; + } + + private UserInfo getAccount() { + UserInfo me = getClient().getAccount(); + return me; + } + + private SmartQQClient getClient() { + return fContactView.getClient(); + } + + private boolean isMySend(long uin) { + UserInfo me = getAccount(); + if (me != null && me.getUin().equals(String.valueOf(uin))) { + return true; + } + return false; + } +} diff --git a/src/cn/ieclipse/smartqq/QQUtils.java b/src/cn/ieclipse/smartqq/QQUtils.java new file mode 100644 index 0000000..c32e095 --- /dev/null +++ b/src/cn/ieclipse/smartqq/QQUtils.java @@ -0,0 +1,64 @@ +/* + * Copyright 2014-2017 ieclipse.cn. + * + * 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 cn.ieclipse.smartqq; + +import cn.ieclipse.smartim.common.IMUtils; +import cn.ieclipse.smartim.model.IContact; +import com.scienjus.smartqq.model.Discuss; +import com.scienjus.smartqq.model.DiscussInfo; +import com.scienjus.smartqq.model.Group; +import com.scienjus.smartqq.model.GroupInfo; + +/** + * 类/接口描述 + * + * @author Jamling + * @date 2018年2月12日 + * + */ +public class QQUtils { + public static char getContactChar(IContact target) { + char ch = 'F'; + if (target instanceof Group || target instanceof GroupInfo) { + ch = 'G'; + } + else if (target instanceof Discuss || target instanceof DiscussInfo) { + ch = 'D'; + } + return ch; + } + + public static String decodeEmoji(String src) { + return src; + // String regex = "\\[\"face\",([1-9][0-9])\\]"; + // if (src != null) { + // String n = src.replaceAll(regex, + // ""); + // return n; + // } + // else { + // return ""; + // } + } + + public static void main(String[] args) { + String src = IMUtils.formatHtmlMsg(true, true, + System.currentTimeMillis(), "Me", + "1毛9[\"face\",0] [\"face\",71] 哈哈"); + System.out.println(src); + System.out.println(decodeEmoji(src)); + } +} diff --git a/src/cn/ieclipse/smartqq/SmartQQPanel.java b/src/cn/ieclipse/smartqq/SmartQQPanel.java index 52f94a6..735a7a2 100644 --- a/src/cn/ieclipse/smartqq/SmartQQPanel.java +++ b/src/cn/ieclipse/smartqq/SmartQQPanel.java @@ -1,10 +1,12 @@ package cn.ieclipse.smartqq; import cn.ieclipse.smartim.IMClientFactory; +import cn.ieclipse.smartim.actions.BroadcastAction; import cn.ieclipse.smartim.console.IMChatConsole; import cn.ieclipse.smartim.model.IContact; import cn.ieclipse.smartim.views.IMContactView; import cn.ieclipse.smartim.views.IMPanel; +import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.project.Project; import com.intellij.openapi.wm.ToolWindow; import com.scienjus.smartqq.client.SmartQQClient; @@ -34,10 +36,11 @@ public IMChatConsole createConsoleUI(IContact contact) { return new QQChatConsole(contact, this); } - // -// private Map consoles = new HashMap<>(); -// -// public QQChatConsole findConsole(String name, boolean add) { -// return consoles.get(name); -// } + @Override + public BroadcastAction createBroadcastAction(DefaultActionGroup group) { + group.add(new QQBroadcastAction(this)); + return null; + } + + } diff --git a/src/cn/ieclipse/wechat/WXBroadcastAction.java b/src/cn/ieclipse/wechat/WXBroadcastAction.java new file mode 100644 index 0000000..79b4317 --- /dev/null +++ b/src/cn/ieclipse/wechat/WXBroadcastAction.java @@ -0,0 +1,19 @@ +package cn.ieclipse.wechat; + +import cn.ieclipse.smartim.actions.BroadcastAction; + +import javax.swing.*; + +public class WXBroadcastAction extends BroadcastAction { + + public WXBroadcastAction(WechatPanel panel) { + super(panel); + } + + @Override + protected void openDialog() { + WXBroadcastDialog dialog = new WXBroadcastDialog((WechatPanel) imPanel); + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } +} diff --git a/src/cn/ieclipse/wechat/WXBroadcastDialog.java b/src/cn/ieclipse/wechat/WXBroadcastDialog.java new file mode 100644 index 0000000..d15d567 --- /dev/null +++ b/src/cn/ieclipse/wechat/WXBroadcastDialog.java @@ -0,0 +1,102 @@ +package cn.ieclipse.wechat; + +import cn.ieclipse.smartim.actions.BroadcastAction; +import cn.ieclipse.smartim.dialogs.BroadcastDialog; +import cn.ieclipse.smartim.model.IMessage; +import cn.ieclipse.smartim.views.ContactTreeMode; +import cn.ieclipse.smartim.views.IMPanel; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.treeStructure.Tree; +import io.github.biezhi.wechat.api.WechatClient; +import io.github.biezhi.wechat.model.Contact; +import io.github.biezhi.wechat.model.WechatMessage; + +import javax.swing.*; +import java.util.List; + +public class WXBroadcastDialog extends BroadcastDialog { + private JTree recentTree; + private JTree friendTree; + private JTree groupTree; + private JTree discussTree; + private WXContactTreeNode root1, root2, root3, root4; + private ContactTreeMode recentModel; + private ContactTreeMode friendModel; + private ContactTreeMode groupModel; + private ContactTreeMode discussModel; + + public WXBroadcastDialog(IMPanel panel) { + super(panel); + } + + @Override + protected void initTab(JTabbedPane host) { + // recentTree = new JTree(); + friendTree = new Tree(); + groupTree = new JTree(); + discussTree = new JTree(); + + // JScrollPane scrollPane1 = new JScrollPane(recentTree); + // tabHost.addTab("最近", null, scrollPane1, null); + + JScrollPane scrollPane2 = new JBScrollPane(friendTree); + tabHost.addTab("好友", null, scrollPane2, null); + + JScrollPane scrollPane3 = new JBScrollPane(groupTree); + tabHost.addTab("群组", null, scrollPane3, null); + + JScrollPane scrollPane4 = new JBScrollPane(discussTree); + tabHost.addTab("讨论组", null, scrollPane4, null); + + initTrees(recentTree, friendTree, groupTree, discussTree); + // root1 = new WXContactTreeNode(false, "recent", imPanel); + root2 = new WXContactTreeNode(false, "friend", imPanel); + root3 = new WXContactTreeNode(false, "group", imPanel); + root4 = new WXContactTreeNode(false, "discuss", imPanel); + root2.update(); + root3.update(); + root4.update(); + + // recentModel = new ContactTreeMode(root1); + friendModel = new ContactTreeMode(root2); + groupModel = new ContactTreeMode(root3); + discussModel = new ContactTreeMode(root4); + + // recentTree.setModel(recentModel); + friendTree.setModel(friendModel); + groupTree.setModel(groupModel); + discussTree.setModel(discussModel); + + } + + protected void sendInternal(String text, List targets) { + WechatClient client = (WechatClient) imPanel.getClient(); + int ret = 0; + if (targets != null) { + for (Object obj : targets) { + if (obj != null && obj instanceof Contact) { + Contact target = (Contact) obj; + try { + IMessage m = createMessage(text, target, client); + client.sendMessage(m, target); + ret++; + } catch (Exception e) { + + } + } + } + } + } + + protected IMessage createMessage(String text, Contact target, + WechatClient client) { + IMessage m = null; + if (!client.isClose()) { + String msg = target.isGroup() + ? text.replace(BroadcastAction.groupMacro, target.getName()) + : text; + m = client.createMessage(WechatMessage.MSGTYPE_TEXT, msg, target); + } + return m; + } +} diff --git a/src/cn/ieclipse/wechat/WXChatConsole.java b/src/cn/ieclipse/wechat/WXChatConsole.java index a8fc5ef..9abe24b 100644 --- a/src/cn/ieclipse/wechat/WXChatConsole.java +++ b/src/cn/ieclipse/wechat/WXChatConsole.java @@ -1,7 +1,6 @@ package cn.ieclipse.wechat; import cn.ieclipse.smartim.IMHistoryManager; -import cn.ieclipse.smartim.SmartClient; import cn.ieclipse.smartim.common.IMUtils; import cn.ieclipse.smartim.console.IMChatConsole; import cn.ieclipse.smartim.model.IContact; @@ -58,6 +57,16 @@ public void post(String msg) { } } + @Override + protected boolean hyperlinkActivated(String desc) { + if (desc.startsWith("weixin://")) { + JOptionPane.showInternalMessageDialog(null, + desc + "为微信专用协议,请使用手机微信打开"); + return false; + } + return super.hyperlinkActivated(desc); + } + @Override public void sendFileInternal(final String file) { // error("暂不支持,敬请关注 https://github.com/Jamling/SmartIM 或 @@ -76,12 +85,10 @@ public void sendFileInternal(final String file) { if (Arrays.asList("png", "jpg", "jpeg", "bmp").contains(ext)) { type = WechatMessage.MSGTYPE_IMAGE; media = "pic"; - } - else if ("gif".equals(ext)) { + } else if ("gif".equals(ext)) { type = WechatMessage.MSGTYPE_EMOTICON; media = "doc"; - } - else { + } else { type = WechatMessage.MSGTYPE_FILE; media = "doc"; } @@ -93,21 +100,23 @@ else if ("gif".equals(ext)) { return; } String link = StringUtils.file2url(file); + String label = file.replace('\\', '/'); String input = null; if (type == WechatMessage.MSGTYPE_EMOTICON || type == WechatMessage.MSGTYPE_IMAGE) { input = String.format("\"%s\"", 0) { input += " width=\"" + uploadInfo.CDNThumbImgWidth + "\""; } if (uploadInfo.CDNThumbImgHeight > 0) { input += " height=\"" + uploadInfo.CDNThumbImgHeight + "\""; } - } - else { input = String.format("%s", link, - file, file); + link, input); + } else { + input = String.format("%s", link, + label, label); content = client.createFileMsgContent(f, uploadInfo.MediaId); } @@ -116,17 +125,12 @@ else if ("gif".equals(ext)) { m.MediaId = uploadInfo.MediaId; client.sendMessage(m, contact); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (!hideMyInput()) { - String name = client.getAccount().getName(); - String msg = IMUtils.formatHtmlMsg(true, false, - System.currentTimeMillis(), name, m.text); - insertDocument(msg); - IMHistoryManager.getInstance().save(client, getUin(), msg); - } - } - }); + if (!hideMyInput()) { + String name = client.getAccount().getName(); + String msg = IMUtils.formatHtmlMsg(true, false, + System.currentTimeMillis(), name, m.text); + insertDocument(msg); + IMHistoryManager.getInstance().save(client, getHistoryFile(), msg); + } } } diff --git a/src/cn/ieclipse/wechat/WXContactTreeNode.java b/src/cn/ieclipse/wechat/WXContactTreeNode.java index 37944e5..0b8b6d6 100644 --- a/src/cn/ieclipse/wechat/WXContactTreeNode.java +++ b/src/cn/ieclipse/wechat/WXContactTreeNode.java @@ -7,7 +7,6 @@ import io.github.biezhi.wechat.api.WechatClient; import io.github.biezhi.wechat.model.Contact; -import javax.swing.tree.DefaultMutableTreeNode; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -17,6 +16,10 @@ * Created by Jamling on 2017/11/1. */ public class WXContactTreeNode extends ContactTreeNode { + public WXContactTreeNode(Object userObject) { + super(userObject); + } + public WXContactTreeNode(boolean check, String name, IMPanel imPanel) { super(check, name, imPanel); } @@ -24,7 +27,7 @@ public WXContactTreeNode(boolean check, String name, IMPanel imPanel) { @Override public void update() { WechatClient client = (WechatClient) imPanel.getClient(); - DefaultMutableTreeNode root = (DefaultMutableTreeNode) getRoot(); + WXContactTreeNode root = (WXContactTreeNode) getRoot(); root.removeAllChildren(); if ("recent".equals(name)) { List list = client.getRecentList(); @@ -33,7 +36,7 @@ public void update() { Collections.sort(list); } for (Contact target : list) { - DefaultMutableTreeNode cn = new DefaultMutableTreeNode( + WXContactTreeNode cn = new WXContactTreeNode( target); root.add(cn); } @@ -44,11 +47,11 @@ public void update() { if (categories != null) { categories.add(0, new VirtualCategory<>("groups", client.getGroupList())); for (VirtualCategory c : categories) { - DefaultMutableTreeNode cn = new DefaultMutableTreeNode(c); + WXContactTreeNode cn = new WXContactTreeNode(c); root.add(cn); if (c.list != null) { for (Contact f : c.list) { - DefaultMutableTreeNode fn = new DefaultMutableTreeNode( + WXContactTreeNode fn = new WXContactTreeNode( f); cn.add(fn); } @@ -59,7 +62,7 @@ public void update() { List list = client.getGroupList(); if (list != null) { for (Contact r : list) { - DefaultMutableTreeNode cn = new DefaultMutableTreeNode(r); + WXContactTreeNode cn = new WXContactTreeNode(r); root.add(cn); } } @@ -67,7 +70,7 @@ public void update() { List list = client.getPublicUsersList(); if (list != null) { for (Contact r : list) { - DefaultMutableTreeNode cn = new DefaultMutableTreeNode(r); + WXContactTreeNode cn = new WXContactTreeNode(r); root.add(cn); } } diff --git a/src/cn/ieclipse/wechat/WXContactView.java b/src/cn/ieclipse/wechat/WXContactView.java index 3bc8b08..65dcb07 100644 --- a/src/cn/ieclipse/wechat/WXContactView.java +++ b/src/cn/ieclipse/wechat/WXContactView.java @@ -1,13 +1,11 @@ package cn.ieclipse.wechat; -import cn.ieclipse.smartim.IMClientFactory; import cn.ieclipse.smartim.IMSendCallback; import cn.ieclipse.smartim.common.LOG; import cn.ieclipse.smartim.views.ContactTreeMode; import cn.ieclipse.smartim.views.IMContactView; import com.intellij.ui.components.JBTabbedPane; import com.intellij.ui.treeStructure.Tree; -import com.scienjus.smartqq.client.SmartQQClient; import io.github.biezhi.wechat.api.WechatClient; import javax.swing.*; diff --git a/src/cn/ieclipse/wechat/WXModificationCallback.java b/src/cn/ieclipse/wechat/WXModificationCallback.java index f8944a9..8e5ddb8 100644 --- a/src/cn/ieclipse/wechat/WXModificationCallback.java +++ b/src/cn/ieclipse/wechat/WXModificationCallback.java @@ -4,8 +4,6 @@ import cn.ieclipse.smartim.model.IContact; import io.github.biezhi.wechat.model.Contact; -import com.scienjus.smartqq.model.QQContact; - /** * Created by Jamling on 2017/11/1. */ diff --git a/src/cn/ieclipse/wechat/WXReceiveCallback.java b/src/cn/ieclipse/wechat/WXReceiveCallback.java index 32fa242..ae4d129 100644 --- a/src/cn/ieclipse/wechat/WXReceiveCallback.java +++ b/src/cn/ieclipse/wechat/WXReceiveCallback.java @@ -17,11 +17,9 @@ import cn.ieclipse.smartim.IMReceiveCallback; import cn.ieclipse.smartim.common.IMUtils; -import cn.ieclipse.smartim.model.impl.AbstractContact; import cn.ieclipse.smartim.model.impl.AbstractFrom; import cn.ieclipse.smartim.model.impl.AbstractMessage; import cn.ieclipse.smartim.settings.SmartIMSettings; -import cn.ieclipse.smartim.views.IMPanel; import io.github.biezhi.wechat.model.Contact; import io.github.biezhi.wechat.model.GroupFrom; import io.github.biezhi.wechat.model.UserFrom; @@ -58,8 +56,7 @@ public void onReceiveMessage(AbstractMessage message, AbstractFrom from) { else { unknown = from.getMember() == null; } - handle(unknown, notify, message, from, - (AbstractContact) from.getContact()); + handle(unknown, notify, message, from, contact); } } @@ -67,20 +64,29 @@ public void onReceiveMessage(AbstractMessage message, AbstractFrom from) { protected String getNotifyContent(AbstractMessage message, AbstractFrom from) { CharSequence content = (from instanceof UserFrom) ? message.getText() - : from.getName() + ":" + message.getText(); + : from.isOut() ? from.getTarget().getName() + : from.getName() + ":" + message.getText(); return content.toString(); } @Override protected String getMsgContent(AbstractMessage message, AbstractFrom from) { - String name = from.getName(); + String name = from.isOut() ? from.getTarget().getName() + : from.getName(); String msg = null; if (message instanceof WechatMessage) { WechatMessage m = (WechatMessage) message; String text = m.getText() == null ? null : m.getText().toString(); boolean encodeHtml = true; + boolean my = from.isOut() ? true : false; if (m.MsgType != WechatMessage.MSGTYPE_TEXT) { encodeHtml = false; + if (m.MsgType == WechatMessage.MSGTYPE_APP + && m.AppMsgType == WechatMessage.APPMSGTYPE_ATTACH) { + if (m.AppMsgInfo != null) { + + } + } } else { if (from instanceof UserFrom) { @@ -88,8 +94,9 @@ protected String getMsgContent(AbstractMessage message, AbstractFrom from) { encodeHtml = !c.isPublic(); } } - msg = IMUtils.formatHtmlMsg(false, encodeHtml, m.CreateTime, name, + msg = IMUtils.formatHtmlMsg(my, encodeHtml, m.CreateTime, name, text); + msg = WXUtils.decodeEmoji(msg); } return msg; } diff --git a/src/cn/ieclipse/wechat/WXUtils.java b/src/cn/ieclipse/wechat/WXUtils.java new file mode 100644 index 0000000..e1b29ee --- /dev/null +++ b/src/cn/ieclipse/wechat/WXUtils.java @@ -0,0 +1,85 @@ +/* + * Copyright 2014-2017 ieclipse.cn. + * + * 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 cn.ieclipse.wechat; + +import cn.ieclipse.smartim.model.IContact; +import cn.ieclipse.util.StringUtils; +import io.github.biezhi.wechat.model.Contact; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 类/接口描述 + * + * @author Jamling + * @date 2018年2月8日 + * + */ +public class WXUtils { + public static char getContactChar(IContact contact) { + if (contact instanceof Contact) { + Contact c = (Contact) contact; + char ch = 'F'; + if (c.isPublic()) { + ch = 'P'; + } + else if (c.isGroup()) { + ch = 'G'; + } + else if (c.is3rdApp() || c.isSpecial()) { + ch = 'S'; + } + return ch; + } + return 0; + } + + public static String decodeEmoji(String src) { + String regex = StringUtils.encodeXml(""); + Pattern p = Pattern.compile(regex, Pattern.MULTILINE); + Matcher m = p.matcher(src); + + List groups = new ArrayList<>(); + List starts = new ArrayList<>(); + List ends = new ArrayList<>(); + while (m.find()) { + starts.add(m.start()); + ends.add(m.end()); + groups.add(m.group()); + } + if (!starts.isEmpty()) { + StringBuilder sb = new StringBuilder(src); + int offset = 0; + for (int i = 0; i < starts.size(); i++) { + int s = starts.get(i); + int e = ends.get(i); + String g = groups.get(i); + + int pos = offset + s; + sb.delete(pos, offset + e); + String ng = g; + ng = StringUtils.decodeXml(g); + sb.insert(pos, ng); + offset += ng.length() - g.length(); + } + return sb.toString(); + } + return src; + } +} diff --git a/src/cn/ieclipse/wechat/WechatPanel.java b/src/cn/ieclipse/wechat/WechatPanel.java index 0bfc6f8..310b722 100644 --- a/src/cn/ieclipse/wechat/WechatPanel.java +++ b/src/cn/ieclipse/wechat/WechatPanel.java @@ -1,10 +1,12 @@ package cn.ieclipse.wechat; import cn.ieclipse.smartim.IMClientFactory; +import cn.ieclipse.smartim.actions.BroadcastAction; import cn.ieclipse.smartim.console.IMChatConsole; import cn.ieclipse.smartim.model.IContact; import cn.ieclipse.smartim.views.IMContactView; import cn.ieclipse.smartim.views.IMPanel; +import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.project.Project; import com.intellij.openapi.wm.ToolWindow; import io.github.biezhi.wechat.api.WechatClient; @@ -31,4 +33,11 @@ public IMContactView createContactsUI() { public IMChatConsole createConsoleUI(IContact contact) { return new WXChatConsole(contact, this); } + + @Override + public BroadcastAction createBroadcastAction(DefaultActionGroup group) { + group.add(new WXBroadcastAction(this)); + return null; + } + } diff --git a/src/icons/SmartIcons.java b/src/icons/SmartIcons.java index b37ec07..1d130e9 100644 --- a/src/icons/SmartIcons.java +++ b/src/icons/SmartIcons.java @@ -15,6 +15,8 @@ public class SmartIcons { public static Icon close = IconLoader.getIcon("/icons/close.png"); public static Icon show = IconLoader.getIcon("/icons/eye.png"); public static Icon hide = IconLoader.getIcon("/icons/eye-slash.png"); + public static Icon broadcast = IconLoader.getIcon("/icons/broadcast.png"); + public static Icon settings = AllIcons.General.Settings; public static Icon group = IconLoader.getIcon("/icons/user-circle.png"); @@ -22,10 +24,11 @@ public class SmartIcons { public static Icon discuss = IconLoader.getIcon("/icons/user-o.png"); public static Icon file = AllIcons.FileTypes.Any_type;//IconLoader.getIcon("/icons/File.png"); + public static Icon projectFile = AllIcons.Toolbar.Folders;//IconLoader.getIcon("/icons/File.png"); public static Icon image = IconLoader.getIcon("/icons/image.png"); public static Icon face = IconLoader.getIcon("/icons/face.png"); public static Icon lock = AllIcons.RunConfigurations.Scroll_down; - public static Icon settings = AllIcons.General.Settings; + public static Icon clear = IconLoader.getIcon("/icons/clear_co.png"); public static void main(String[] args) { System.out.println(group);