├── .gitignore ├── README.md ├── api ├── pom.xml └── src │ └── main │ └── java │ └── iqq │ └── api │ ├── annotation │ └── IMEventHandler.java │ ├── bean │ ├── IMAccount.java │ ├── IMBuddy.java │ ├── IMBuddyCategory.java │ ├── IMCategory.java │ ├── IMDevice.java │ ├── IMEntity.java │ ├── IMMsg.java │ ├── IMRoom.java │ ├── IMRoomCategory.java │ ├── IMStatus.java │ ├── IMUser.java │ └── content │ │ ├── IMContentItem.java │ │ ├── IMContentType.java │ │ ├── IMFaceItem.java │ │ ├── IMPictureItem.java │ │ └── IMTextItem.java │ ├── common │ ├── EventBase.java │ └── Intent.java │ └── event │ ├── IMEvent.java │ ├── IMEventAware.java │ ├── IMEventDispatcher.java │ ├── IMEventListener.java │ ├── IMEventType.java │ └── args │ └── LoginRequest.java ├── main ├── config.xml ├── lib │ ├── jhrome-2.0.jar │ └── weblaf-1.29.jar ├── pom.xml └── src │ ├── main │ ├── java │ │ └── iqq │ │ │ └── app │ │ │ ├── IMLauncher.java │ │ │ ├── api │ │ │ ├── Conn.java │ │ │ ├── IMRequest.java │ │ │ ├── IMResponse.java │ │ │ └── User.java │ │ │ ├── core │ │ │ ├── annotation │ │ │ │ ├── IMModule.java │ │ │ │ ├── IMQuery.java │ │ │ │ └── IMService.java │ │ │ ├── context │ │ │ │ └── IMContext.java │ │ │ ├── module │ │ │ │ ├── AddFriendModule.java │ │ │ │ ├── LogicModule.java │ │ │ │ ├── MsgModule.java │ │ │ │ └── SessionModule.java │ │ │ ├── query │ │ │ │ ├── AccountQuery.java │ │ │ │ ├── BuddyQuery.java │ │ │ │ ├── GroupQuery.java │ │ │ │ └── MsgQuery.java │ │ │ ├── service │ │ │ │ ├── ConfigService.java │ │ │ │ ├── EventService.java │ │ │ │ ├── HttpService.java │ │ │ │ ├── I18nService.java │ │ │ │ ├── ResourceService.java │ │ │ │ ├── SkinService.java │ │ │ │ ├── TaskService.java │ │ │ │ ├── TimerService.java │ │ │ │ └── impl │ │ │ │ │ ├── EventServiceImpl.java │ │ │ │ │ ├── HttpServiceImpl.java │ │ │ │ │ ├── I18nServiceImpl.java │ │ │ │ │ ├── ResourceServiceImpl.java │ │ │ │ │ ├── SkinServiceImpl.java │ │ │ │ │ ├── TaskServiceImpl.java │ │ │ │ │ └── TimerServiceImpl.java │ │ │ └── store │ │ │ │ └── IMDataStore.java │ │ │ ├── ui │ │ │ ├── IMContentPane.java │ │ │ ├── IMDialog.java │ │ │ ├── IMFrame.java │ │ │ ├── IMFrameWrap.java │ │ │ ├── IMPanel.java │ │ │ ├── IMTree.java │ │ │ ├── action │ │ │ │ ├── IMActionHandler.java │ │ │ │ └── IMActionHandlerProxy.java │ │ │ ├── border │ │ │ │ ├── RoundBorder.java │ │ │ │ ├── ShadeBorder.java │ │ │ │ └── TabContentPanelBorder.java │ │ │ ├── component │ │ │ │ ├── StatusButton.java │ │ │ │ └── TitleComponent.java │ │ │ ├── dialog │ │ │ │ └── TipDialog.java │ │ │ ├── event │ │ │ │ ├── UIEvent.java │ │ │ │ ├── UIEventDispatcher.java │ │ │ │ ├── UIEventHandler.java │ │ │ │ ├── UIEventListener.java │ │ │ │ ├── UIEventType.java │ │ │ │ └── args │ │ │ │ │ └── LoginInfoParam.java │ │ │ ├── frame │ │ │ │ ├── AddCategoryFrame.java │ │ │ │ ├── AddFriendFrame.java │ │ │ │ ├── ChatFrame.java │ │ │ │ ├── ChooseCategoryFrame.java │ │ │ │ ├── GetFriendRequestFrame.java │ │ │ │ ├── LoginFrame.java │ │ │ │ ├── MainFrame.java │ │ │ │ ├── SkinFrame.java │ │ │ │ ├── VerifyFrame.java │ │ │ │ └── panel │ │ │ │ │ ├── chat │ │ │ │ │ ├── BasicPanel.java │ │ │ │ │ ├── ChatPane.java │ │ │ │ │ ├── RoomPanel.java │ │ │ │ │ ├── UserPanel.java │ │ │ │ │ ├── msg │ │ │ │ │ │ ├── MsgGroupPanel.java │ │ │ │ │ │ └── MsgPane.java │ │ │ │ │ ├── picloader │ │ │ │ │ │ ├── AbstractPicLoader.java │ │ │ │ │ │ ├── PicLoadListener.java │ │ │ │ │ │ ├── PicLoadState.java │ │ │ │ │ │ ├── PicLoader.java │ │ │ │ │ │ ├── PicLoaderFactory.java │ │ │ │ │ │ └── UserPicLoader.java │ │ │ │ │ └── rich │ │ │ │ │ │ ├── RichTextPane.java │ │ │ │ │ │ ├── UIBasicItem.java │ │ │ │ │ │ ├── UIFaceItem.java │ │ │ │ │ │ ├── UILinkItem.java │ │ │ │ │ │ ├── UILoaderPicItem.java │ │ │ │ │ │ ├── UIRichComponent.java │ │ │ │ │ │ ├── UIRichItem.java │ │ │ │ │ │ ├── UISkinPicItem.java │ │ │ │ │ │ └── UITextItem.java │ │ │ │ │ ├── login │ │ │ │ │ ├── LoginPane.java │ │ │ │ │ └── LoginingPane.java │ │ │ │ │ └── main │ │ │ │ │ ├── FooterPanel.java │ │ │ │ │ ├── HeaderPanel.java │ │ │ │ │ ├── MainPane.java │ │ │ │ │ └── MiddlePanel.java │ │ │ ├── manager │ │ │ │ ├── ChatManager.java │ │ │ │ ├── FrameManager.java │ │ │ │ ├── MainManager.java │ │ │ │ └── SkinManager.java │ │ │ ├── renderer │ │ │ │ ├── BoddyTreeCellRenderer.java │ │ │ │ ├── CategoryComboxCellRenderer.java │ │ │ │ ├── RecentTreeCellRenderer.java │ │ │ │ ├── RoomTreeCellRenderer.java │ │ │ │ └── node │ │ │ │ │ ├── BuddyNode.java │ │ │ │ │ ├── CategoryNode.java │ │ │ │ │ ├── EntityNode.java │ │ │ │ │ └── RoomNode.java │ │ │ └── skin │ │ │ │ └── Skin.java │ │ │ └── util │ │ │ ├── Benchmark.java │ │ │ ├── StatusUtils.java │ │ │ ├── UIUtils.java │ │ │ ├── XmlUtils.java │ │ │ ├── date │ │ │ ├── BaseDate.java │ │ │ ├── Date.java │ │ │ ├── DateTime.java │ │ │ ├── DateTimeZone.java │ │ │ ├── DateUtils.java │ │ │ └── FriendlyDate.java │ │ │ └── gson │ │ │ ├── DateFormatter.java │ │ │ ├── DateTimeFormatter.java │ │ │ ├── DateTimeZoneFormatter.java │ │ │ └── GsonUtils.java │ └── resources │ │ ├── META-INF │ │ └── MANIFEST.MF │ │ ├── logback.xml │ │ └── spring-config.xml │ └── test │ └── java │ └── iqq │ └── app │ ├── TestIoc.java │ ├── TestPath.java │ ├── service │ ├── TestI18nService.java │ ├── TestResourceService.java │ └── TestSkinService.java │ ├── ui │ └── TestLogin.java │ └── util │ └── TestXml.java ├── pom.xml ├── resources ├── i18n │ ├── appBundle.properties │ └── appBundle_zh_CN.properties ├── icons │ ├── default │ │ ├── qq_icon.png │ │ └── qq_icon.svg │ ├── login │ │ ├── avatar.jpg │ │ ├── avatar.png │ │ ├── avatar2.png │ │ ├── captcha.jpg │ │ ├── face.jpg │ │ ├── group.png │ │ └── qq_icon.png │ └── status │ │ ├── away.png │ │ ├── callme.png │ │ ├── hidden.png │ │ ├── meeting.png │ │ ├── offline.png │ │ ├── online.png │ │ └── silent.png ├── pom.xml └── screenshots │ ├── chat-msg.png │ ├── chat.png │ ├── main-skin.png │ ├── main-skin2.png │ └── main.png └── skin-default ├── chat ├── bg │ ├── balloon │ │ ├── balloon_left_blue.9.png │ │ ├── balloon_left_green.9.png │ │ ├── balloon_left_white.9.png │ │ ├── balloon_right_blue.9.png │ │ └── balloon_right_grey.9.png │ └── nav_bg.9.png └── icons │ ├── inputbar │ ├── emoticon.png │ ├── fileTransfere.png │ ├── history.png │ ├── noMessage.png │ ├── offMessage.png │ ├── pictures.png │ ├── screenCapture.png │ ├── send.png │ ├── shake.png │ └── text.png │ └── setting_icon.png ├── font └── wqy-microhei.ttc ├── login ├── bg │ ├── footer_bg.9.png │ ├── login_bg.9.png │ └── login_bg2.9.png └── icons │ ├── key.png │ ├── setting.png │ └── setting_active.png ├── main ├── bg │ ├── search_bg.9.png │ └── tab_bg.9.png └── icons │ ├── arrow_down.png │ ├── arrow_left.png │ ├── search_icon.png │ ├── tab_boddy.png │ ├── tab_group.png │ ├── tab_recent.png │ └── toolbar │ ├── add.png │ ├── mail.png │ ├── msg_new.png │ ├── msg_normal.png │ ├── msgrecode.png │ ├── qzone.png │ ├── setting.png │ └── weibo.png ├── pom.xml ├── skin.xml ├── skin ├── bg │ ├── 0.9.png │ ├── 1.9.png │ ├── 10.9.png │ ├── 11.9.png │ ├── 12.9.png │ ├── 13.9.png │ ├── 14.9.png │ ├── 2.9.png │ ├── 3.9.png │ ├── 4.9.png │ ├── 5.9.png │ ├── 6.9.png │ ├── 7.9.png │ ├── 8.9.png │ └── 9.9.png └── icons │ └── skin_icon.png └── window ├── bg ├── transparent.9.png └── window_bg.9.png └── icons ├── close.png ├── close_active.png ├── maximize.png ├── maximize_active.png ├── minimize.png ├── minimize_active.png ├── restore.png ├── restore_active.png ├── setting.png ├── setting_active.png ├── skin.png ├── skin_active.png ├── title_icon.png ├── title_w_icon.png └── title_w_icon_black.png /.gitignore: -------------------------------------------------------------------------------- 1 | # iqq working dir 2 | /iqq.log* 3 | /user 4 | 5 | # Build artifacts 6 | artifacts 7 | target 8 | classes 9 | 10 | # IDE & module files 11 | .idea 12 | *.iml 13 | .project 14 | .settings 15 | .classpath 16 | workspace.xml 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 这是一个正在开发的项目,您可以把页面加入书签随时看看我们的进度,也希望您将来能够来看看我们最终的程序。 2 | 3 | 我们目标 4 | 5 | 提供一个基于WebQQ协议开发的库,您可以基于这个库让您的程序集成QQ相关的功能 6 | 提供一个即开即用的桌面QQ客户端,风格可能类似于Mac版QQ 7 | 8 | 项目 9 | IQQ UI: https://github.com/im-qq/iqq.git 10 | IQQ Core: https://github.com/im-qq/webqq-core.git 11 | 12 | 加入开发 13 | 14 | 我们热情的欢迎热衷于开源项目的童鞋加入到开发中来,您可以加入讨论群(164158750)一起讨论项目的方向和进度。 15 | 16 | 百度网盘下载: 17 | http://pan.baidu.com/share/home?uk=3071047022 18 | 19 | 原项目地址:https://code.google.com/p/iqq/ 20 | 21 | 新版本截图: 22 | ![image](https://raw.githubusercontent.com/im-qq/iqq/master/resources/screenshots/chat-msg.png) 23 | ![image](https://raw.githubusercontent.com/im-qq/iqq/master/resources/screenshots/chat.png) 24 | ![image](https://raw.githubusercontent.com/im-qq/iqq/master/resources/screenshots/main.png) 25 | ![image](https://raw.githubusercontent.com/im-qq/iqq/master/resources/screenshots/main-skin2.png) 26 | ![image](https://raw.githubusercontent.com/im-qq/iqq/master/resources/screenshots/main-skin.png) 27 | -------------------------------------------------------------------------------- /api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | iqq.app 9 | iqq 10 | 3.0.0-SNAPSHOT 11 | 12 | 13 | iqq-api 14 | 3.0.0-SNAPSHOT 15 | iqq api module 16 | 17 | 18 | 19 | org.slf4j 20 | slf4j-api 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/annotation/IMEventHandler.java: -------------------------------------------------------------------------------- 1 | package iqq.api.annotation; /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import iqq.api.event.IMEventType; 19 | 20 | import java.lang.annotation.ElementType; 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | import java.lang.annotation.Target; 24 | 25 | /** 26 | * 事件处理注解,如果在方法上写上了这个注解,则说明此方法处理对应的消息 27 | *

28 | * Project : iqq 29 | * Author : solosky < solosky772@qq.com > 30 | * Created : 4/13/14 31 | * License : Apache License 2.0 32 | */ 33 | @Target(ElementType.METHOD) 34 | @Retention(RetentionPolicy.RUNTIME) 35 | public @interface IMEventHandler { 36 | public IMEventType value(); 37 | } 38 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/IMAccount.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean; 2 | 3 | /** 4 | * Project : iqq-projects 5 | * Author : 承∮诺 < 6208317@qq.com > 6 | * Created : 14-5-4 7 | * License : Apache License 2.0 8 | */ 9 | public class IMAccount extends IMUser { 10 | private String account; 11 | private String password; 12 | private boolean isRememberPwd; 13 | 14 | public String getAccount() { 15 | return account; 16 | } 17 | 18 | public void setAccount(String account) { 19 | this.account = account; 20 | } 21 | 22 | public String getPassword() { 23 | return password; 24 | } 25 | 26 | public void setPassword(String password) { 27 | this.password = password; 28 | } 29 | 30 | public boolean isRememberPwd() { 31 | return isRememberPwd; 32 | } 33 | 34 | public void setRememberPwd(boolean isRememberPwd) { 35 | this.isRememberPwd = isRememberPwd; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/IMBuddy.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: solosky 6 | * Date: 4/19/14 7 | * Time: 8:05 PM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public class IMBuddy extends IMUser { 11 | private String remark; 12 | 13 | public String getRemark() { 14 | return remark; 15 | } 16 | 17 | public void setRemark(String remark) { 18 | this.remark = remark; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/IMBuddyCategory.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean; 2 | 3 | import java.io.Serializable; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | 7 | /** 8 | * Project : iqq-projects 9 | * Author : 承∮诺 < 6208317@qq.com > 10 | * Created : 14-5-8 11 | * License : Apache License 2.0 12 | */ 13 | public class IMBuddyCategory extends IMCategory implements Serializable { 14 | private List buddyList = new LinkedList(); 15 | 16 | public List getBuddyList() { 17 | return buddyList; 18 | } 19 | 20 | public void setBuddyList(List buddyList) { 21 | this.buddyList = buddyList; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/IMCategory.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Project : iqq-projects 7 | * Author : 承∮诺 < 6208317@qq.com > 8 | * Created : 14-5-9 9 | * License : Apache License 2.0 10 | */ 11 | public class IMCategory implements Serializable { 12 | private String id; 13 | private String name; 14 | 15 | public String getId() { 16 | return id; 17 | } 18 | 19 | public void setId(String id) { 20 | this.id = id; 21 | } 22 | 23 | public String getName() { 24 | return name; 25 | } 26 | 27 | public void setName(String name) { 28 | this.name = name; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return "IMCategory{" + 34 | "id='" + id + '\'' + 35 | ", name='" + name + '\'' + 36 | '}'; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/IMDevice.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: solosky 6 | * Date: 4/19/14 7 | * Time: 8:02 PM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public enum IMDevice { 11 | PC, WEB, IPAD, IPHONE, ANDROID, OTHER 12 | } 13 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/IMEntity.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean; 2 | 3 | import java.awt.image.BufferedImage; 4 | import java.io.Serializable; 5 | 6 | /** 7 | * Created with IntelliJ IDEA. 8 | * User: solosky 9 | * Date: 4/19/14 10 | * Time: 7:49 PM 11 | * To change this template use File | Settings | File Templates. 12 | */ 13 | public class IMEntity implements Serializable { 14 | private String id; 15 | private String nick; 16 | private String sign; 17 | private String avatar; 18 | private BufferedImage avatarBuffered; 19 | 20 | private Object attachment; 21 | 22 | public String getId() { 23 | return id; 24 | } 25 | 26 | public void setId(String id) { 27 | this.id = id; 28 | } 29 | 30 | public String getNick() { 31 | return nick; 32 | } 33 | 34 | public void setNick(String nick) { 35 | this.nick = nick; 36 | } 37 | 38 | public String getSign() { 39 | return sign; 40 | } 41 | 42 | public void setSign(String sign) { 43 | this.sign = sign; 44 | } 45 | 46 | public String getAvatar() { 47 | return avatar; 48 | } 49 | 50 | public void setAvatar(String avatar) { 51 | this.avatar = avatar; 52 | } 53 | 54 | public BufferedImage getAvatarBuffered() { 55 | return avatarBuffered; 56 | } 57 | 58 | public void setAvatarBuffered(BufferedImage avatarBuffered) { 59 | this.avatarBuffered = avatarBuffered; 60 | } 61 | 62 | public Object getAttachment() { 63 | return attachment; 64 | } 65 | 66 | public void setAttachment(Object attachment) { 67 | this.attachment = attachment; 68 | } 69 | 70 | @Override 71 | public String toString() { 72 | return "IMEntity{" + 73 | "id='" + id + '\'' + 74 | ", nick='" + nick + '\'' + 75 | ", sign='" + sign + '\'' + 76 | ", avatar='" + avatar + '\'' + 77 | ", avatarBuffered=" + avatarBuffered + 78 | '}'; 79 | } 80 | 81 | @Override 82 | public boolean equals(Object o) { 83 | if (this == o) return true; 84 | if (o == null || getClass() != o.getClass()) return false; 85 | 86 | IMEntity entity = (IMEntity) o; 87 | 88 | return id.equals(entity.id); 89 | 90 | } 91 | 92 | @Override 93 | public int hashCode() { 94 | return id.hashCode(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/IMRoom.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean; 2 | 3 | /** 4 | * Project : iqq-projects 5 | * Author : 承∮诺 < 6208317@qq.com > 6 | * Created : 14-5-9 7 | * License : Apache License 2.0 8 | */ 9 | public class IMRoom extends IMEntity { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/IMRoomCategory.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean; 2 | 3 | import java.util.LinkedList; 4 | import java.util.List; 5 | 6 | /** 7 | * Project : iqq-projects 8 | * Author : 承∮诺 < 6208317@qq.com > 9 | * Created : 14-5-9 10 | * License : Apache License 2.0 11 | */ 12 | public class IMRoomCategory extends IMCategory { 13 | private List roomList = new LinkedList<>(); 14 | 15 | public List getRoomList() { 16 | return roomList; 17 | } 18 | 19 | public void setRoomList(List roomList) { 20 | this.roomList = roomList; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/IMStatus.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: solosky 6 | * Date: 4/19/14 7 | * Time: 8:01 PM 8 | * To change this template use File | Settings | File Templates. 9 | *

10 | * 状态 0离线,1在线,2离开,3请勿打扰,4忙碌,5Q我吧,6隐身 11 | */ 12 | public enum IMStatus { 13 | 14 | OFFLINE("offline", 0), 15 | ONLINE("online", 1), 16 | AWAY("away", 2), 17 | SILENT("silent", 3), 18 | MEETING("meeting", 4), 19 | CALLME("callme", 5), 20 | HIDDEN("hidden", 6); 21 | 22 | public String name; 23 | public int value; 24 | 25 | IMStatus(String name, int value) { 26 | this.name = name; 27 | this.value = value; 28 | } 29 | 30 | /** 31 | * 原生值转枚举 32 | * 33 | * @param value 34 | * @return 35 | */ 36 | public static IMStatus valueOfRaw(int value) { 37 | for (IMStatus status : IMStatus.values()) { 38 | if (status.value == value) { 39 | return status; 40 | } 41 | } 42 | return OFFLINE; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/IMUser.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean; 2 | 3 | /** 4 | * Created with IntelliJ IDEA. 5 | * User: solosky 6 | * Date: 4/19/14 7 | * Time: 7:48 PM 8 | * To change this template use File | Settings | File Templates. 9 | */ 10 | public class IMUser extends IMEntity { 11 | private IMStatus status; 12 | 13 | public IMStatus getStatus() { 14 | return status; 15 | } 16 | 17 | public void setStatus(IMStatus status) { 18 | this.status = status; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/content/IMContentItem.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean.content; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * 聊天内容接口 7 | *

8 | * Project : iqq-projects 9 | * Author : 承∮诺 < 6208317@qq.com > 10 | * Created : 14-5-15 11 | * License : Apache License 2.0 12 | */ 13 | public interface IMContentItem extends Serializable { 14 | public IMContentType getType(); 15 | } 16 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/content/IMContentType.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean.content; 2 | 3 | /** 4 | * Project : iqq-projects 5 | * Author : 承∮诺 < 6208317@qq.com > 6 | * Created : 14-5-15 7 | * License : Apache License 2.0 8 | */ 9 | public enum IMContentType { 10 | TEXT, FACE, PIC 11 | } 12 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/content/IMFaceItem.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean.content; 2 | 3 | /** 4 | * 聊天表情信息 5 | *

6 | * Project : iqq-projects 7 | * Author : 承∮诺 < 6208317@qq.com > 8 | * Created : 14-5-15 9 | * License : Apache License 2.0 10 | */ 11 | public class IMFaceItem implements IMContentItem { 12 | private String key; 13 | 14 | @Override 15 | public IMContentType getType() { 16 | return IMContentType.FACE; 17 | } 18 | 19 | public String getKey() { 20 | return key; 21 | } 22 | 23 | public void setKey(String key) { 24 | this.key = key; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return "[表情 " + key + "]"; 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/content/IMPictureItem.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean.content; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * 聊天图片信息 7 | *

8 | * Project : iqq-projects 9 | * Author : 承∮诺 < 6208317@qq.com > 10 | * Created : 14-5-15 11 | * License : Apache License 2.0 12 | */ 13 | public class IMPictureItem implements IMContentItem { 14 | private File file; 15 | 16 | @Override 17 | public IMContentType getType() { 18 | return IMContentType.PIC; 19 | } 20 | 21 | public File getFile() { 22 | return file; 23 | } 24 | 25 | public void setFile(File file) { 26 | this.file = file; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "[图片 " + file + "]"; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/bean/content/IMTextItem.java: -------------------------------------------------------------------------------- 1 | package iqq.api.bean.content; 2 | 3 | /** 4 | * 聊天文本信息 5 | *

6 | * Project : iqq-projects 7 | * Author : 承∮诺 < 6208317@qq.com > 8 | * Created : 14-5-15 9 | * License : Apache License 2.0 10 | */ 11 | public class IMTextItem implements IMContentItem { 12 | private String text; 13 | 14 | public IMTextItem(String text) { 15 | this.text = text; 16 | } 17 | 18 | @Override 19 | public IMContentType getType() { 20 | return IMContentType.TEXT; 21 | } 22 | 23 | public String getText() { 24 | return text; 25 | } 26 | 27 | public void setText(String text) { 28 | this.text = text; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return text; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/common/EventBase.java: -------------------------------------------------------------------------------- 1 | package iqq.api.common; 2 | /* 3 | * Licensed to the Apache Software Foundation (ASF) under one or more 4 | * contributor license agreements. See the NOTICE file distributed with 5 | * this work for additional information regarding copyright ownership. 6 | * The ASF licenses this file to You under the Apache License, Version 2.0 7 | * (the "License"); you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import java.io.Serializable; 20 | 21 | /** 22 | * Project : iqq 23 | * Author : solosky < solosky772@qq.com > 24 | * Created : 6/14/14 25 | * License : Apache License 2.0 26 | */ 27 | public class EventBase extends Intent implements Serializable { 28 | protected int eventId; 29 | protected Object target; 30 | protected EventBase relatedEvent; 31 | 32 | public int getEventId() { 33 | return eventId; 34 | } 35 | 36 | public void setEventId(int eventId) { 37 | this.eventId = eventId; 38 | } 39 | 40 | public Object getTarget() { 41 | return target; 42 | } 43 | 44 | public void setTarget(Object target) { 45 | this.target = target; 46 | } 47 | 48 | public EventBase getRelatedEvent() { 49 | return relatedEvent; 50 | } 51 | 52 | public void setRelatedEvent(EventBase relatedEvent) { 53 | this.relatedEvent = relatedEvent; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/common/Intent.java: -------------------------------------------------------------------------------- 1 | package iqq.api.common; 2 | /* 3 | * Licensed to the Apache Software Foundation (ASF) under one or more 4 | * contributor license agreements. See the NOTICE file distributed with 5 | * this work for additional information regarding copyright ownership. 6 | * The ASF licenses this file to You under the Apache License, Version 2.0 7 | * (the "License"); you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import java.io.Serializable; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | /** 24 | * Project : iqq 25 | * Author : solosky < solosky772@qq.com > 26 | * Created : 6/14/14 27 | * License : Apache License 2.0 28 | */ 29 | public class Intent implements Serializable { 30 | protected Map dataMap = new HashMap(); 31 | 32 | public void putData(String key, Object value) { 33 | this.dataMap.put(key, value); 34 | } 35 | 36 | public boolean hasData(String key) { 37 | return this.dataMap.containsKey(key); 38 | } 39 | 40 | public T getData(String key) { 41 | return (T) this.dataMap.get(key); 42 | } 43 | 44 | public int getInt(String key) { 45 | return getDataEx(key); 46 | } 47 | 48 | public long getLong(String key) { 49 | return getDataEx(key); 50 | } 51 | 52 | public boolean getBoolean(String key) { 53 | return getDataEx(key); 54 | } 55 | 56 | public String getString(String key) { 57 | return getDataEx(key); 58 | } 59 | 60 | private T getDataEx(String key) { 61 | if (hasData(key)) { 62 | return (T) getData(key); 63 | } 64 | return null; 65 | } 66 | 67 | public Map getDataEx() { 68 | return dataMap; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/event/IMEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2 20 | * Package : iqq.action 21 | * File : IMEvent.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-3-10 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.api.event; 27 | 28 | 29 | import iqq.api.common.EventBase; 30 | 31 | import java.io.Serializable; 32 | 33 | /** 34 | * 35 | * IM事件,作为所有操作的数据的载体在多个模块中传递消息 36 | * 37 | * @author solosky 38 | * 39 | */ 40 | public class IMEvent extends EventBase implements Serializable { 41 | private static final long serialVersionUID = 1L; 42 | private IMEventType type; 43 | 44 | public IMEvent(IMEventType type) { 45 | this.type = type; 46 | } 47 | 48 | public IMEvent() { 49 | } 50 | 51 | public IMEvent(IMEventType type, Object data) { 52 | this.type = type; 53 | this.setTarget(data); 54 | } 55 | 56 | 57 | public IMEventType getType() { 58 | return type; 59 | } 60 | 61 | public void setType(IMEventType type) { 62 | this.type = type; 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | return "IMEvent{" + 68 | "type=" + type + 69 | '}'; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/event/IMEventAware.java: -------------------------------------------------------------------------------- 1 | package iqq.api.event; /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : iqq 20 | * Author : solosky < solosky772@qq.com > 21 | * Created : 5/1/14 22 | * License : Apache License 2.0 23 | */ 24 | public interface IMEventAware { 25 | public void setIMEventListener(IMEventListener imEventListener); 26 | } 27 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/event/IMEventDispatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.action 21 | * File : IMEventHandlerProxy.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-3-16 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.api.event; 27 | 28 | import iqq.api.annotation.IMEventHandler; 29 | import org.slf4j.Logger; 30 | import org.slf4j.LoggerFactory; 31 | 32 | import java.lang.reflect.Method; 33 | import java.util.HashMap; 34 | import java.util.Map; 35 | 36 | /** 37 | * 使用这个类简化事件的注册,分发 38 | * 只需在被代理的类使用@IMEventHandler注解需要处理的事件类型即可 39 | * 40 | * @author solosky 41 | */ 42 | public class IMEventDispatcher implements IMEventListener { 43 | private static final Logger LOG = LoggerFactory.getLogger(IMEventDispatcher.class); 44 | private Map methodMap = new HashMap(); 45 | 46 | public IMEventDispatcher() { 47 | for (Method m : this.getClass().getDeclaredMethods()) { 48 | if (m.isAnnotationPresent(IMEventHandler.class)) { 49 | IMEventHandler handler = m.getAnnotation(IMEventHandler.class); 50 | this.methodMap.put(handler.value(), m); 51 | if (!m.isAccessible()) { 52 | m.setAccessible(true); 53 | } 54 | } 55 | } 56 | for (Method m : this.getClass().getMethods()) { 57 | if (m.isAnnotationPresent(IMEventHandler.class)) { 58 | IMEventHandler handler = m.getAnnotation(IMEventHandler.class); 59 | this.methodMap.put(handler.value(), m); 60 | if (!m.isAccessible()) { 61 | m.setAccessible(true); 62 | } 63 | } 64 | } 65 | } 66 | 67 | @Override 68 | public void onIMEvent(IMEvent imEvent) { 69 | Method m = methodMap.get(imEvent.getType()); 70 | if (m != null) { 71 | try { 72 | m.invoke(this, imEvent); 73 | } catch (Throwable e) { 74 | LOG.warn("invoke IMEventHandler Error!! {}.{}(..)", getClass(), m.getName(), e); 75 | } 76 | } else { 77 | LOG.warn("IMEventHandler Not Found!! imEvent = {}", imEvent); 78 | } 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/event/IMEventListener.java: -------------------------------------------------------------------------------- 1 | package iqq.api.event; 2 | 3 | /** 4 | * IM事件监听器 5 | */ 6 | public interface IMEventListener { 7 | /** 8 | * 触发事件回掉 9 | * 10 | * @param imEvent 11 | */ 12 | public void onIMEvent(IMEvent imEvent); 13 | } 14 | -------------------------------------------------------------------------------- /api/src/main/java/iqq/api/event/args/LoginRequest.java: -------------------------------------------------------------------------------- 1 | package iqq.api.event.args; 2 | /* 3 | * Licensed to the Apache Software Foundation (ASF) under one or more 4 | * contributor license agreements. See the NOTICE file distributed with 5 | * this work for additional information regarding copyright ownership. 6 | * The ASF licenses this file to You under the Apache License, Version 2.0 7 | * (the "License"); you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import iqq.api.bean.IMStatus; 20 | 21 | /** 22 | * Project : iqq 23 | * Author : solosky < solosky772@qq.com > 24 | * Created : 5/1/14 25 | * License : Apache License 2.0 26 | */ 27 | public class LoginRequest { 28 | private String username; 29 | private String password; 30 | private IMStatus status; 31 | 32 | public String getUsername() { 33 | return username; 34 | } 35 | 36 | public void setUsername(String username) { 37 | this.username = username; 38 | } 39 | 40 | public String getPassword() { 41 | return password; 42 | } 43 | 44 | public void setPassword(String password) { 45 | this.password = password; 46 | } 47 | 48 | public IMStatus getStatus() { 49 | return status; 50 | } 51 | 52 | public void setStatus(IMStatus status) { 53 | this.status = status; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /main/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | test123 5 | 6 | iqqv3 7 | 8 | 9 | -------------------------------------------------------------------------------- /main/lib/jhrome-2.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/main/lib/jhrome-2.0.jar -------------------------------------------------------------------------------- /main/lib/weblaf-1.29.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/main/lib/weblaf-1.29.jar -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/IMLauncher.java: -------------------------------------------------------------------------------- 1 | package iqq.app; 2 | 3 | import iqq.app.core.context.IMContext; 4 | import iqq.app.ui.manager.FrameManager; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 8 | import org.springframework.context.annotation.ComponentScan; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | import javax.swing.*; 12 | import java.io.File; 13 | 14 | /** 15 | * 引导启动类 16 | *

17 | * Project : iqq 18 | * Author : 承∮诺 < 6208317@qq.com > 19 | * Created : 14-4-17 20 | * License : Apache License 2.0 21 | */ 22 | @Configuration 23 | @ComponentScan("iqq.app") 24 | public class IMLauncher { 25 | private static final Logger LOG = LoggerFactory.getLogger(IMLauncher.class); 26 | 27 | /** 28 | * 程序入口 29 | * 30 | * @param args 31 | */ 32 | public static void main(String[] args) { 33 | SwingUtilities.invokeLater(new Runnable() { 34 | @Override 35 | public void run() { 36 | init(); 37 | startup(); 38 | } 39 | }); 40 | } 41 | 42 | /** 43 | * 启动前配置 44 | */ 45 | private static void init() { 46 | // APP路径 47 | String path = System.getProperty("user.dir"); 48 | if (new File(path + File.separator + "resources").exists()) { 49 | System.setProperty("app.dir", new File(path).getAbsolutePath()); 50 | } else { 51 | // 去掉了最后一个main目录 52 | path = path.substring(0, path.lastIndexOf(File.separator)); 53 | System.setProperty("app.dir", new File(path).getAbsolutePath()); 54 | } 55 | LOG.info("app.dir = " + System.getProperty("app.dir")); 56 | 57 | // 关闭勾子 58 | Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { 59 | @Override 60 | public void run() { 61 | shutdown(); 62 | } 63 | })); 64 | LOG.info("init..."); 65 | } 66 | 67 | /** 68 | * 运行程序环境 69 | */ 70 | private static void startup() { 71 | IMContext.init(new AnnotationConfigApplicationContext("iqq.app")); 72 | 73 | FrameManager frameManager = IMContext.getBean(FrameManager.class); 74 | frameManager.showLogin(); 75 | } 76 | 77 | /** 78 | * 程序关闭 79 | */ 80 | private static void shutdown() { 81 | LOG.info("shutdown..."); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/api/Conn.java: -------------------------------------------------------------------------------- 1 | package iqq.app.api; 2 | 3 | /** 4 | * Created by Tony on 4/22/15. 5 | */ 6 | public class Conn { 7 | private String key; 8 | 9 | public String getKey() { 10 | return key; 11 | } 12 | 13 | public void setKey(String key) { 14 | this.key = key; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/api/IMRequest.java: -------------------------------------------------------------------------------- 1 | package iqq.app.api; 2 | 3 | import iqq.app.util.gson.GsonUtils; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by Tony on 4/22/15. 10 | */ 11 | public class IMRequest { 12 | private String command; 13 | private Object data; 14 | 15 | public String getCommand() { 16 | return command; 17 | } 18 | 19 | public void setCommand(String command) { 20 | this.command = command; 21 | } 22 | 23 | public Object getData() { 24 | return data; 25 | } 26 | 27 | public void setData(Object data) { 28 | this.data = data; 29 | } 30 | 31 | public void setData(String key, Object value) { 32 | Map map = new HashMap<>(); 33 | map.put(key, value); 34 | 35 | data = map; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/api/IMResponse.java: -------------------------------------------------------------------------------- 1 | package iqq.app.api; 2 | 3 | import com.google.gson.JsonObject; 4 | import com.google.gson.JsonParser; 5 | import iqq.app.util.gson.GsonUtils; 6 | 7 | /** 8 | * Created by Tony on 4/22/15. 9 | */ 10 | public class IMResponse { 11 | private int status; 12 | private String msg; 13 | private JsonObject data; 14 | private String refer; 15 | 16 | public int getStatus() { 17 | return status; 18 | } 19 | 20 | public void setStatus(int status) { 21 | this.status = status; 22 | } 23 | 24 | public String getMsg() { 25 | return msg; 26 | } 27 | 28 | public void setMsg(String msg) { 29 | this.msg = msg; 30 | } 31 | 32 | public JsonObject getData() { 33 | return data; 34 | } 35 | 36 | public void setData(JsonObject data) { 37 | this.data = data; 38 | } 39 | 40 | public String getRefer() { 41 | return refer; 42 | } 43 | 44 | public void setRefer(String refer) { 45 | this.refer = refer; 46 | } 47 | 48 | public static IMResponse parseJson(String json) { 49 | try { 50 | return GsonUtils.fromJson(json, IMResponse.class); 51 | } catch (Exception e) { 52 | JsonObject object = new JsonParser().parse(json).getAsJsonObject(); 53 | IMResponse response = new IMResponse(); 54 | response.setStatus(object.get("status").getAsInt()); 55 | response.setMsg(object.get("msg").getAsString()); 56 | response.setRefer(object.get("refer").getAsString()); 57 | return response; 58 | } 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return "ApiData{" + 64 | "status=" + status + 65 | ", msg='" + msg + '\'' + 66 | ", data='" + data + '\'' + 67 | ", refer='" + refer + '\'' + 68 | '}'; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/api/User.java: -------------------------------------------------------------------------------- 1 | package iqq.app.api; 2 | 3 | /** 4 | * Created by Tony on 4/22/15. 5 | */ 6 | public class User { 7 | private String id; 8 | private String nick; 9 | private String avatar; 10 | private String status; 11 | private String token; 12 | 13 | public String getId() { 14 | return id; 15 | } 16 | 17 | public void setId(String id) { 18 | this.id = id; 19 | } 20 | 21 | public String getNick() { 22 | return nick; 23 | } 24 | 25 | public void setNick(String nick) { 26 | this.nick = nick; 27 | } 28 | 29 | public String getAvatar() { 30 | return avatar; 31 | } 32 | 33 | public void setAvatar(String avatar) { 34 | this.avatar = avatar; 35 | } 36 | 37 | public String getStatus() { 38 | return status; 39 | } 40 | 41 | public void setStatus(String status) { 42 | this.status = status; 43 | } 44 | 45 | public String getToken() { 46 | return token; 47 | } 48 | 49 | public void setToken(String token) { 50 | this.token = token; 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return "User{" + 56 | "id='" + id + '\'' + 57 | ", nick='" + nick + '\'' + 58 | ", avatar='" + avatar + '\'' + 59 | ", status='" + status + '\'' + 60 | ", token='" + token + '\'' + 61 | '}'; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/annotation/IMModule.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.annotation; /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : iqq 20 | * Author : solosky < solosky772@qq.com > 21 | * Created : 4/13/14 22 | * License : Apache License 2.0 23 | */ 24 | public @interface IMModule { 25 | } 26 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/annotation/IMQuery.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.annotation; /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : iqq 20 | * Author : solosky < solosky772@qq.com > 21 | * Created : 4/13/14 22 | * License : Apache License 2.0 23 | */ 24 | public @interface IMQuery { 25 | } 26 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/annotation/IMService.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.annotation; /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 19 | /** 20 | * Project : iqq 21 | * Author : solosky < solosky772@qq.com > 22 | * Created : 4/13/14 23 | * License : Apache License 2.0 24 | */ 25 | public @interface IMService { 26 | } 27 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/context/IMContext.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.context; 2 | /* 3 | * Licensed to the Apache Software Foundation (ASF) under one or more 4 | * contributor license agreements. See the NOTICE file distributed with 5 | * this work for additional information regarding copyright ownership. 6 | * The ASF licenses this file to You under the Apache License, Version 2.0 7 | * (the "License"); you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import org.springframework.context.ApplicationContext; 20 | 21 | /** 22 | * 客户端上下文,所有的创建的对象实例都由上下文管理,也可以从这个类得到任意对象 23 | * 通常来说,不需要直接使用这个类,因为所有的对象都是通过依赖注入的方式自动注入的 24 | * 只有在一些特定的场景,比如某些对象不是由容器管理的情况下才需要使用这个类获得容器中的对象或者创建对象 25 | * Project : iqq 26 | * Author : solosky < solosky772@qq.com > 27 | * Created : 4/13/14 28 | * License : Apache License 2.0 29 | */ 30 | public class IMContext { 31 | // /**ioc容器*/ 32 | // private Ioc ioc; 33 | 34 | private ApplicationContext applicationContext; 35 | 36 | private static IMContext singleton = new IMContext(); 37 | 38 | public static IMContext me() { 39 | return singleton; 40 | } 41 | 42 | public static void init(ApplicationContext ctx) { 43 | me().applicationContext = ctx; 44 | } 45 | 46 | private IMContext() { 47 | // applicationContext = new ClassPathXmlApplicationContext("classpath:spring-config.xml"); 48 | // applicationContext = new AnnotationConfigApplicationContext("iqq.app"); 49 | } 50 | 51 | public static T getBean(Class clazz) { 52 | return singleton.applicationContext.getBean(clazz); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/module/MsgModule.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.module; 2 | 3 | import iqq.api.bean.IMMsg; 4 | import iqq.app.core.query.MsgQuery; 5 | import iqq.app.core.service.EventService; 6 | import iqq.app.ui.event.UIEvent; 7 | import iqq.app.ui.event.UIEventDispatcher; 8 | import iqq.app.ui.event.UIEventHandler; 9 | import iqq.app.ui.event.UIEventType; 10 | import org.springframework.stereotype.Service; 11 | 12 | import javax.annotation.PostConstruct; 13 | import javax.annotation.Resource; 14 | import java.util.HashMap; 15 | import java.util.LinkedList; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | /** 20 | * 消息处理模块 21 | *

22 | * Created by Tony on 5/3/15. 23 | */ 24 | @Service 25 | public class MsgModule implements MsgQuery { 26 | @Resource 27 | private EventService eventService; 28 | private Map> msgsMap = new HashMap<>(); 29 | 30 | @PostConstruct 31 | public void init() { 32 | 33 | UIEventDispatcher uiEventDispatcher = new UIEventDispatcher(this); 34 | eventService.register(uiEventDispatcher.getEventTypes(), uiEventDispatcher); 35 | } 36 | 37 | @UIEventHandler(UIEventType.RECV_RAW_MSG) 38 | private void onMsgRecvEvent(UIEvent uiEvent) { 39 | IMMsg msg = (IMMsg) uiEvent.getTarget(); 40 | String id = msg.getSender().getId(); 41 | if (!msgsMap.containsKey(id)) { 42 | msgsMap.put(id, new LinkedList<>()); 43 | } 44 | msgsMap.get(id).add(msg); 45 | } 46 | 47 | @UIEventHandler(UIEventType.SEND_MSG_REQUEST) 48 | private void onSendMsgEvent(UIEvent uiEvent) { 49 | IMMsg msg = (IMMsg) uiEvent.getTarget(); 50 | String id = msg.getOwner().getId(); 51 | if (!msgsMap.containsKey(id)) { 52 | msgsMap.put(id, new LinkedList<>()); 53 | } 54 | msgsMap.get(id).add(msg); 55 | } 56 | 57 | @Override 58 | public List getMsgs(String uid) { 59 | if (!msgsMap.containsKey(uid)) { 60 | msgsMap.put(uid, new LinkedList<>()); 61 | } 62 | return msgsMap.get(uid); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/module/SessionModule.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.module; 2 | 3 | import iqq.api.bean.IMEntity; 4 | import iqq.api.bean.IMMsg; 5 | import iqq.api.bean.IMUser; 6 | import iqq.app.core.service.EventService; 7 | import iqq.app.ui.event.UIEvent; 8 | import iqq.app.ui.event.UIEventDispatcher; 9 | import iqq.app.ui.event.UIEventHandler; 10 | import iqq.app.ui.event.UIEventType; 11 | import org.springframework.stereotype.Service; 12 | 13 | import javax.annotation.PostConstruct; 14 | import javax.annotation.Resource; 15 | import java.util.*; 16 | 17 | /** 18 | * 会话模块 19 | *

20 | * Created by Tony on 5/3/15. 21 | */ 22 | @Service 23 | public class SessionModule { 24 | 25 | @Resource 26 | private EventService eventService; 27 | private Set entities = new HashSet<>(); 28 | 29 | @PostConstruct 30 | public void init() { 31 | 32 | UIEventDispatcher uiEventDispatcher = new UIEventDispatcher(this); 33 | eventService.register(uiEventDispatcher.getEventTypes(), uiEventDispatcher); 34 | } 35 | 36 | @UIEventHandler(UIEventType.SHOW_CHAT) 37 | private void onShowChatEvent(UIEvent uiEvent) { 38 | IMEntity entity = (IMEntity) uiEvent.getTarget(); 39 | entities.add(entity); 40 | 41 | eventService.broadcast(new UIEvent(UIEventType.FLASH_USER_STOP, entity)); 42 | } 43 | 44 | @UIEventHandler(UIEventType.CLOSE_CHAT) 45 | private void onCloseChatEvent(UIEvent uiEvent) { 46 | IMEntity entity = (IMEntity) uiEvent.getTarget(); 47 | entities.remove(entity); 48 | } 49 | 50 | @UIEventHandler(UIEventType.RECV_RAW_MSG) 51 | private void onMsgRecvEvent(UIEvent uiEvent) { 52 | IMMsg msg = (IMMsg) uiEvent.getTarget(); 53 | 54 | IMEntity sender = msg.getSender(); 55 | if (!entities.contains(sender)) { 56 | eventService.broadcast(new UIEvent(UIEventType.FLASH_USER_START, sender)); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/query/AccountQuery.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.query; 2 | 3 | import iqq.api.bean.IMAccount; 4 | 5 | /** 6 | * Created by Tony on 4/7/15. 7 | */ 8 | public interface AccountQuery { 9 | 10 | public IMAccount getOwner(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/query/BuddyQuery.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.query; 2 | /* 3 | * Licensed to the Apache Software Foundation (ASF) under one or more 4 | * contributor license agreements. See the NOTICE file distributed with 5 | * this work for additional information regarding copyright ownership. 6 | * The ASF licenses this file to You under the Apache License, Version 2.0 7 | * (the "License"); you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import iqq.api.bean.IMBuddy; 20 | 21 | import java.util.List; 22 | 23 | /** 24 | * 好友列表查询接口 25 | * Project : iqq 26 | * Author : solosky < solosky772@qq.com > 27 | * Created : 4/13/14 28 | * License : Apache License 2.0 29 | */ 30 | public interface BuddyQuery { 31 | public IMBuddy findById(String id); 32 | 33 | public List findAll(); 34 | } 35 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/query/GroupQuery.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.query; /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * 群和讨论组查询 20 | * Project : iqq 21 | * Author : solosky < solosky772@qq.com > 22 | * Created : 4/13/14 23 | * License : Apache License 2.0 24 | */ 25 | public interface GroupQuery { 26 | } 27 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/query/MsgQuery.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.query; 2 | /* 3 | * Licensed to the Apache Software Foundation (ASF) under one or more 4 | * contributor license agreements. See the NOTICE file distributed with 5 | * this work for additional information regarding copyright ownership. 6 | * The ASF licenses this file to You under the Apache License, Version 2.0 7 | * (the "License"); you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import iqq.api.bean.IMMsg; 20 | 21 | import java.util.List; 22 | 23 | /** 24 | * QQ消息查询 25 | * Project : iqq 26 | * Author : solosky < solosky772@qq.com > 27 | * Created : 4/13/14 28 | * License : Apache License 2.0 29 | */ 30 | public interface MsgQuery { 31 | List getMsgs(String uid); 32 | } 33 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/service/ConfigService.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.service; 2 | /* 3 | * Licensed to the Apache Software Foundation (ASF) under one or more 4 | * contributor license agreements. See the NOTICE file distributed with 5 | * this work for additional information regarding copyright ownership. 6 | * The ASF licenses this file to You under the Apache License, Version 2.0 7 | * (the "License"); you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | /** 20 | * Project : iqq 21 | * Author : solosky < solosky772@qq.com > 22 | * Created : 4/13/14 23 | * License : Apache License 2.0 24 | */ 25 | public interface ConfigService { 26 | } 27 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/service/EventService.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.service; 2 | /* 3 | * Licensed to the Apache Software Foundation (ASF) under one or more 4 | * contributor license agreements. See the NOTICE file distributed with 5 | * this work for additional information regarding copyright ownership. 6 | * The ASF licenses this file to You under the Apache License, Version 2.0 7 | * (the "License"); you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import iqq.app.ui.event.UIEvent; 20 | import iqq.app.ui.event.UIEventListener; 21 | import iqq.app.ui.event.UIEventType; 22 | 23 | /** 24 | * Project : iqq 25 | * Author : solosky < solosky772@qq.com > 26 | * Created : 5/3/14 27 | * License : Apache License 2.0 28 | */ 29 | public interface EventService { 30 | 31 | /** 32 | * 注册自己感兴趣的事件到事件中心 33 | * 如果该模块被卸载或者禁用了,请务必取消注册 34 | * 35 | * @param intrestedEvents 感兴趣的事件ID,可以是多个 36 | * @param listener 监听器 37 | */ 38 | public void register(UIEventType[] intrestedEvents, UIEventListener listener); 39 | 40 | /** 41 | * 只注销已经注册特定的事件监听器 42 | * 43 | * @param intrestedEvents 44 | * @param listener 45 | */ 46 | public void unregister(UIEventType[] intrestedEvents, UIEventListener listener); 47 | 48 | /** 49 | * 注销和指定监听器所有感兴趣的事件 50 | * 51 | * @param listener 52 | */ 53 | public void unregister(UIEventListener listener); 54 | 55 | 56 | /** 57 | * 广播一个事件,所有对这个感兴趣的监听器都会被调用 58 | * 59 | * @param event 60 | */ 61 | public void broadcast(UIEvent event); 62 | } 63 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/service/HttpService.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.service; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Created by Tony on 4/21/15. 7 | */ 8 | public interface HttpService { 9 | 10 | void doGet(String url, StringCallback callback); 11 | 12 | void doPost(String url, Map params, StringCallback callback); 13 | 14 | interface StringCallback { 15 | void onSuccess(String content); 16 | 17 | void onFailure(int statusCode, String content); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/service/I18nService.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.service; /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import iqq.app.core.annotation.IMService; 19 | 20 | import java.util.Locale; 21 | 22 | /** 23 | * Project : iqq 24 | * Author : solosky < solosky772@qq.com > 25 | * Created : 4/13/14 26 | * License : Apache License 2.0 27 | */ 28 | @IMService 29 | public interface I18nService { 30 | 31 | /** 32 | * 根据设置的语言获取国际化资源 33 | * 34 | * @param messageKey 35 | * @return 36 | */ 37 | public String getMessage(String messageKey); 38 | 39 | /** 40 | * 根据设置的语言获取国际化资源,支持格式化串 41 | * 42 | * @param messageKey 43 | * @param params 44 | * @return 45 | */ 46 | public String getMessage(String messageKey, Object... params); 47 | 48 | /** 49 | * 根据固定语言获取国际化资源 50 | * 51 | * @param messageKey 52 | * @param locale 53 | * @return 54 | */ 55 | public String getMessage(String messageKey, Locale locale); 56 | 57 | /** 58 | * 根据固定语言获取国际化资源,支持格式化串 59 | * 60 | * @param messageKey 61 | * @param locale 62 | * @param params 63 | * @return 64 | */ 65 | public String getMessage(String messageKey, Locale locale, Object... params); 66 | 67 | /** 68 | * 获取当前语言 69 | * 70 | * @return 71 | */ 72 | public Locale getCurrentLocale(); 73 | 74 | /** 75 | * 获取国际化资源文件目录 76 | * 77 | * @return 78 | */ 79 | public String getI18nDirectory(); 80 | } 81 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/service/ResourceService.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.service; 2 | /* 3 | * Licensed to the Apache Software Foundation (ASF) under one or more 4 | * contributor license agreements. See the NOTICE file distributed with 5 | * this work for additional information regarding copyright ownership. 6 | * The ASF licenses this file to You under the Apache License, Version 2.0 7 | * (the "License"); you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import javax.swing.*; 20 | import java.io.File; 21 | 22 | /** 23 | * 资源文件获取服务 24 | *

25 | * Project : iqq 26 | * Author : solosky < solosky772@qq.com > 27 | * Created : 4/13/14 28 | * License : Apache License 2.0 29 | */ 30 | public interface ResourceService { 31 | /** 32 | * 获取绝对资源目录 33 | * 34 | * @return 35 | */ 36 | public String getResourcePath(); 37 | 38 | /** 39 | * 获取资源文件 40 | * 41 | * @param filename 42 | * @return 43 | */ 44 | public File getFile(String filename); 45 | 46 | 47 | /** 48 | * 获取资源文件图片 49 | * 50 | * @param filename 51 | * @return 52 | */ 53 | public ImageIcon getIcon(String filename); 54 | 55 | 56 | /** 57 | * 获取资源文件图片,调整为固定大小 58 | * 59 | * @param filename 60 | * @param width 61 | * @param height 62 | * @return 63 | */ 64 | public ImageIcon getIcon(String filename, int width, int height); 65 | 66 | 67 | /** 68 | * 获取用户目录 69 | * 70 | * @return 71 | */ 72 | public String getUserPath(); 73 | 74 | /** 75 | * 获取用户目录下面的文件 76 | * 77 | * @param filename 78 | * @return 79 | */ 80 | public File getUserFile(String filename); 81 | 82 | 83 | /** 84 | * 获取资源文件图片 85 | * 86 | * @param filename 87 | * @return 88 | */ 89 | public ImageIcon getUserIcon(String filename); 90 | 91 | 92 | /** 93 | * 获取资源文件图片,调整为固定大小 94 | * 95 | * @param filename 96 | * @param width 97 | * @param height 98 | * @return 99 | */ 100 | public ImageIcon getUserIcon(String filename, int width, int height); 101 | 102 | 103 | } 104 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/service/SkinService.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.service; 2 | 3 | import com.alee.extended.painter.Painter; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | 8 | /** 9 | * Project : iqq-projects 10 | * Author : 承∮诺 < 6208317@qq.com > 11 | * Created : 14-4-15 12 | * License : Apache License 2.0 13 | */ 14 | public interface SkinService { 15 | 16 | /** 17 | * 获取颜色 18 | * 19 | * @return 20 | */ 21 | public Color getColorByKey(String key); 22 | 23 | /** 24 | * 获取图标 25 | * 26 | * @param key 27 | * @return 28 | */ 29 | public ImageIcon getIconByKey(String key); 30 | 31 | /** 32 | * 获取资源文件图片,调整为固定大小 33 | * 34 | * @param filename 35 | * @param width 36 | * @param height 37 | * @return 38 | */ 39 | public ImageIcon getIconByKey(String key, int width, int height); 40 | 41 | /** 42 | * 获取点9图的Painter 43 | * 44 | * @param key 45 | * @return 46 | */ 47 | public Painter getPainterByKey(String key); 48 | 49 | /** 50 | * 获取默认的皮肤配置文件 51 | * 52 | * @return 53 | */ 54 | public String getDefaultConfig(); 55 | 56 | /** 57 | * 获取自定义皮肤目录 58 | * 59 | * @return 60 | */ 61 | public String getDirectory(); 62 | 63 | /** 64 | * 设置自定义皮肤目录 65 | * 66 | * @param path 67 | */ 68 | public void setDirectory(String path); 69 | 70 | /** 71 | * 是否启用了自定义皮肤 72 | * 73 | * @return 74 | */ 75 | public boolean isEnabledCustom(); 76 | 77 | /** 78 | * 设置启用自定义皮肤 79 | * 80 | * @param enable 81 | */ 82 | public void setEnableCustom(boolean enable); 83 | 84 | /** 85 | * 设置默认字体 86 | * 87 | * @param vFont 88 | */ 89 | public void setDefaultFont(Font vFont); 90 | } 91 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/service/TaskService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.service 21 | * File : IMTaskService.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-3-25 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.core.service; 27 | 28 | 29 | /** 30 | * 31 | * 异步任务执行 32 | * 可以把一些可能比较耗时的任务单独放在另外一个线程处理,如IO操作等 33 | * 34 | * @author solosky 35 | * 36 | */ 37 | public interface TaskService { 38 | public void submit(Runnable runnable); 39 | 40 | public void submit(Object target, String method, Object... args); 41 | } 42 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/service/TimerService.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.service; 2 | 3 | /** 4 | * Created by Tony on 5/3/15. 5 | */ 6 | public interface TimerService { 7 | 8 | void setInterval(Runnable runnable, long interval); 9 | 10 | void setTimeout(Runnable runnable, long delay); 11 | 12 | void killTimer(Runnable runnable); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/service/impl/HttpServiceImpl.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.service.impl; 2 | 3 | import iqq.app.core.service.HttpService; 4 | import org.apache.http.HttpResponse; 5 | import org.apache.http.HttpStatus; 6 | import org.apache.http.NameValuePair; 7 | import org.apache.http.client.HttpClient; 8 | import org.apache.http.client.entity.UrlEncodedFormEntity; 9 | import org.apache.http.client.methods.HttpGet; 10 | import org.apache.http.client.methods.HttpPost; 11 | import org.apache.http.impl.client.DefaultHttpClient; 12 | import org.apache.http.message.BasicNameValuePair; 13 | import org.apache.http.util.EntityUtils; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import org.springframework.stereotype.Service; 17 | 18 | import java.io.IOException; 19 | import java.io.UnsupportedEncodingException; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.concurrent.ExecutorService; 24 | import java.util.concurrent.Executors; 25 | 26 | /** 27 | * Created by Tony on 4/21/15. 28 | */ 29 | @Service 30 | public class HttpServiceImpl implements HttpService { 31 | private Logger logger = LoggerFactory.getLogger(HttpServiceImpl.class); 32 | 33 | private ExecutorService poolExecutor = Executors.newCachedThreadPool(); 34 | private HttpClient client = new DefaultHttpClient(); 35 | 36 | @Override 37 | public void doGet(String url, StringCallback callback) { 38 | logger.debug("doGet " + url); 39 | poolExecutor.submit(new Runnable() { 40 | @Override 41 | public void run() { 42 | HttpGet request = new HttpGet(url); 43 | try { 44 | HttpResponse response = client.execute(request); 45 | if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { 46 | String content = EntityUtils.toString(response.getEntity()); 47 | callback.onSuccess(content); 48 | } else { 49 | callback.onFailure(response.getStatusLine().getStatusCode(), ""); 50 | } 51 | } catch (IOException e) { 52 | e.printStackTrace(); 53 | } 54 | } 55 | }); 56 | } 57 | 58 | @Override 59 | public void doPost(String url, Map params, StringCallback callback) { 60 | logger.debug("doPost " + url + " " + params); 61 | 62 | poolExecutor.submit(new Runnable() { 63 | @Override 64 | public void run() { 65 | HttpPost request = new HttpPost(url); 66 | List formparams = new ArrayList<>(); 67 | for (String key : params.keySet()) { 68 | formparams.add(new BasicNameValuePair(key, params.get(key))); 69 | } 70 | try { 71 | request.setEntity(new UrlEncodedFormEntity(formparams, "UTF-8")); 72 | } catch (UnsupportedEncodingException e) { 73 | e.printStackTrace(); 74 | } 75 | try { 76 | HttpResponse response = client.execute(request); 77 | if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { 78 | String content = EntityUtils.toString(response.getEntity()); 79 | callback.onSuccess(content); 80 | } else { 81 | callback.onFailure(response.getStatusLine().getStatusCode(), ""); 82 | } 83 | } catch (IOException e) { 84 | e.printStackTrace(); 85 | } 86 | } 87 | }); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/service/impl/ResourceServiceImpl.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.service.impl; 2 | 3 | import iqq.app.core.service.ResourceService; 4 | import org.springframework.stereotype.Service; 5 | 6 | import javax.swing.*; 7 | import java.io.File; 8 | 9 | /** 10 | * 资源文件获取服务 11 | *

12 | * #还没有加入缓存优化 13 | *

14 | * Project : iqq 15 | * Author : 承∮诺 < 6208317@qq.com > 16 | * Created : 14-4-17 17 | * License : Apache License 2.0 18 | */ 19 | @Service 20 | public class ResourceServiceImpl implements ResourceService { 21 | /** 22 | * 资源文件目录 23 | */ 24 | public static final String RESOURCES_DIR = System.getProperty("app.dir", System.getProperty("user.dir")) + File.separator + "resources" + File.separator; 25 | 26 | public static final String USER_DIR = "user" + File.separator; 27 | 28 | /** 29 | * 获取绝对资源目录 30 | * 31 | * @return 32 | */ 33 | @Override 34 | public String getResourcePath() { 35 | return RESOURCES_DIR; 36 | } 37 | 38 | /** 39 | * 获取资源文件 40 | * 41 | * @param filename 42 | * @return 43 | */ 44 | @Override 45 | public File getFile(String filename) { 46 | return new File(RESOURCES_DIR + filename); 47 | } 48 | 49 | /** 50 | * 获取资源文件图片 51 | * 52 | * @param filename 53 | * @return 54 | */ 55 | @Override 56 | public ImageIcon getIcon(String filename) { 57 | return new ImageIcon(getFile(filename).getAbsolutePath()); 58 | } 59 | 60 | /** 61 | * 获取资源文件图片,调整为固定大小 62 | * 63 | * @param filename 64 | * @param width 65 | * @param height 66 | * @return 67 | */ 68 | @Override 69 | public ImageIcon getIcon(String filename, int width, int height) { 70 | return new ImageIcon(getIcon(filename).getImage().getScaledInstance(width, height, 100)); 71 | } 72 | 73 | /** 74 | * 获取用户目录 75 | * 76 | * @return 77 | */ 78 | @Override 79 | public String getUserPath() { 80 | return getResourcePath() + USER_DIR; 81 | } 82 | 83 | /** 84 | * 获取用户目录下面的文件 85 | * 86 | * @param filename 87 | * @return 88 | */ 89 | @Override 90 | public File getUserFile(String filename) { 91 | return new File(RESOURCES_DIR + filename); 92 | } 93 | 94 | /** 95 | * 获取资源文件图片 96 | * 97 | * @param filename 98 | * @return 99 | */ 100 | @Override 101 | public ImageIcon getUserIcon(String filename) { 102 | return new ImageIcon(getUserFile(filename).getAbsolutePath()); 103 | } 104 | 105 | /** 106 | * 获取资源文件图片,调整为固定大小 107 | * 108 | * @param filename 109 | * @param width 110 | * @param height 111 | * @return 112 | */ 113 | @Override 114 | public ImageIcon getUserIcon(String filename, int width, int height) { 115 | return new ImageIcon(getUserIcon(filename).getImage().getScaledInstance(width, height, 100)); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/service/impl/TaskServiceImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.service.impl 21 | * File : IMTaskServiceImpl.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-3-25 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.core.service.impl; 27 | 28 | 29 | import iqq.app.core.service.TaskService; 30 | import org.slf4j.Logger; 31 | import org.slf4j.LoggerFactory; 32 | import org.springframework.stereotype.Service; 33 | 34 | import java.lang.reflect.Method; 35 | import java.util.concurrent.ExecutorService; 36 | import java.util.concurrent.Executors; 37 | 38 | /** 39 | * @author solosky 40 | */ 41 | @Service 42 | public class TaskServiceImpl implements TaskService { 43 | private final Logger logger = LoggerFactory.getLogger(TaskServiceImpl.class); 44 | private ExecutorService threads = Executors.newFixedThreadPool(2); 45 | 46 | @Override 47 | public void submit(Runnable runnable) { 48 | threads.submit(runnable); 49 | } 50 | 51 | @Override 52 | public void submit(final Object target, final String method, final Object... args) { 53 | threads.submit(new Runnable() { 54 | public void run() { 55 | for (Method m : target.getClass().getDeclaredMethods()) { 56 | if (m.getName().equals(method)) { 57 | try { 58 | if (!m.isAccessible()) { 59 | m.setAccessible(true); 60 | } 61 | m.invoke(target, args); 62 | return; 63 | } catch (Throwable e) { 64 | logger.warn("invoke method error!!", e); 65 | } 66 | } 67 | } 68 | } 69 | }); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/service/impl/TimerServiceImpl.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.service.impl; 2 | 3 | import iqq.app.core.service.TimerService; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.beans.factory.InitializingBean; 7 | import org.springframework.stereotype.Service; 8 | 9 | import javax.swing.*; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.Timer; 13 | import java.util.TimerTask; 14 | 15 | /** 16 | * 默认定时器实现 17 | *

18 | * Created by Tony on 5/3/15. 19 | */ 20 | @Service 21 | public class TimerServiceImpl implements TimerService, InitializingBean { 22 | 23 | private static Logger LOG = LoggerFactory.getLogger(TimerServiceImpl.class); 24 | private Timer timer; 25 | private Map map; 26 | 27 | @Override 28 | public void afterPropertiesSet() throws Exception { 29 | timer = new Timer(); 30 | map = new HashMap<>(); 31 | } 32 | 33 | @Override 34 | public void setInterval(Runnable runnable, long interval) { 35 | TimerAdapter adapter = new TimerAdapter(runnable); 36 | map.put(runnable, adapter); 37 | timer.schedule(adapter, interval, interval); 38 | } 39 | 40 | @Override 41 | public void setTimeout(Runnable runnable, long delay) { 42 | TimerAdapter adapter = new TimerAdapter(runnable); 43 | map.put(runnable, adapter); 44 | timer.schedule(adapter, delay); 45 | } 46 | 47 | @Override 48 | public void killTimer(Runnable runnable) { 49 | if (map.containsKey(runnable)) { 50 | TimerAdapter adapter = map.get(runnable); 51 | adapter.cancel(); 52 | timer.purge(); 53 | } 54 | } 55 | 56 | private static class TimerAdapter extends TimerTask { 57 | private Runnable runnable; 58 | 59 | public TimerAdapter(Runnable runnable) { 60 | this.runnable = runnable; 61 | } 62 | 63 | @Override 64 | public void run() { 65 | SwingUtilities.invokeLater(new Runnable() { 66 | @Override 67 | public void run() { 68 | try { 69 | runnable.run(); 70 | } catch (Throwable e) { 71 | LOG.warn("TimerAdapter run timer error!", e); 72 | } 73 | } 74 | }); 75 | } 76 | 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/core/store/IMDataStore.java: -------------------------------------------------------------------------------- 1 | package iqq.app.core.store; /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import iqq.api.bean.IMBuddy; 19 | 20 | /** 21 | * Project : iqq 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 5/3/14 24 | * License : Apache License 2.0 25 | */ 26 | public interface IMDataStore { 27 | public void addBuddy(IMBuddy buddy); 28 | 29 | public void removeBuddyById(long id); 30 | } 31 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/IMContentPane.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui; 2 | 3 | /** 4 | * Project : iqq-projects 5 | * Author : 承∮诺 < 6208317@qq.com > 6 | * Created : 14-5-11 7 | * License : Apache License 2.0 8 | */ 9 | public class IMContentPane extends IMPanel { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/IMFrameWrap.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui; 2 | 3 | import com.alee.extended.painter.NinePatchIconPainter; 4 | import com.alee.extended.painter.Painter; 5 | import com.alee.laf.panel.WebPanel; 6 | import com.alee.utils.NinePatchUtils; 7 | import com.alee.utils.SystemUtils; 8 | import iqq.app.core.service.SkinService; 9 | import iqq.app.ui.skin.Skin; 10 | 11 | /** 12 | * 窗口阴影背景 13 | *

14 | * Project : iqq-projects 15 | * Author : 承∮诺 < 6208317@qq.com > 16 | * Created : 14-5-5 17 | * License : Apache License 2.0 18 | */ 19 | public class IMFrameWrap extends WebPanel implements Skin { 20 | 21 | @Override 22 | public void installSkin(SkinService skinService) { 23 | // 背景只带了阴影,就只是一个底而已 24 | // mac下忽略背影 25 | if (!SystemUtils.isMac()) { 26 | Painter painter = new NinePatchIconPainter(NinePatchUtils.getShadeIcon(20, 1, 0.75f)); 27 | setPainter(painter); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/IMPanel.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui; 2 | 3 | import com.alee.laf.panel.WebPanel; 4 | import iqq.app.core.service.SkinService; 5 | import iqq.app.ui.skin.Skin; 6 | 7 | /** 8 | * 面板封装类 9 | *

10 | * Project : iqq-projects 11 | * Author : 承∮诺 < 6208317@qq.com > 12 | * Created : 14-5-7 13 | * License : Apache License 2.0 14 | */ 15 | public class IMPanel extends WebPanel implements Skin { 16 | public IMPanel() { 17 | this.setOpaque(false); 18 | } 19 | 20 | @Override 21 | public void installSkin(SkinService skinService) { 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/IMTree.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui; 2 | 3 | import com.alee.extended.tree.WebAsyncTree; 4 | import com.alee.laf.tree.WebTreeUI; 5 | import iqq.app.core.service.SkinService; 6 | import iqq.app.ui.skin.Skin; 7 | 8 | import javax.swing.*; 9 | import javax.swing.tree.TreeSelectionModel; 10 | import java.awt.*; 11 | import java.awt.geom.RoundRectangle2D; 12 | 13 | /** 14 | * 树组件,继承于weblaf的异步加载树组件 15 | *

16 | * Project : iqq-projects 17 | * Author : 承∮诺 < 6208317@qq.com > 18 | * Created : 14-5-8 19 | * License : Apache License 2.0 20 | */ 21 | public class IMTree extends WebAsyncTree implements Skin { 22 | 23 | public IMTree() { 24 | this.setPaintLines(false); 25 | this.setOpaque(false); 26 | this.setRootVisible(false); 27 | this.setShowsRootHandles(false); 28 | this.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 29 | this.setUI(new IMTreeUI()); 30 | } 31 | 32 | @Override 33 | public void installSkin(SkinService skinService) { 34 | 35 | } 36 | 37 | class IMTreeUI extends WebTreeUI { 38 | public Color selectedBg = new Color(240, 220, 147); 39 | public Color rolloverBg = new Color(178, 212, 243); 40 | 41 | /** 42 | * 选中时画背景 43 | * 44 | * @param g2d 45 | */ 46 | @Override 47 | protected void paintSelection(Graphics2D g2d) { 48 | if (tree.getSelectionCount() > 0) { 49 | // Draw final selections 50 | final java.util.List selections = getSelectionRects(); 51 | for (final Rectangle rect : selections) { 52 | g2d.setPaint(selectedBg); 53 | g2d.fill(new RoundRectangle2D.Double(rect.x + selectionShadeWidth, rect.y + selectionShadeWidth, 54 | rect.width - selectionShadeWidth * 2 - 1, rect.height - selectionShadeWidth * 2 - 1, 0, 55 | 0)); 56 | } 57 | } 58 | } 59 | 60 | /** 61 | * 鼠标经过画背景 62 | * 63 | * @param g2d 64 | */ 65 | @Override 66 | protected void paintRolloverNodeHighlight(Graphics2D g2d) { 67 | if (tree.isEnabled() && highlightRolloverNode && rolloverRow != -1 && !tree.isRowSelected(rolloverRow)) { 68 | final Rectangle rect = isFullLineSelection() ? getFullRowBounds(rolloverRow) : tree.getRowBounds(rolloverRow); 69 | if (rect != null) { 70 | //final Composite old = LafUtils.setupAlphaComposite ( g2d, 0.35f ); 71 | g2d.setPaint(rolloverBg); 72 | g2d.fill(new RoundRectangle2D.Double(rect.x + selectionShadeWidth, rect.y + selectionShadeWidth, 73 | rect.width - selectionShadeWidth * 2 - 1, rect.height - selectionShadeWidth * 2 - 1, 0, 74 | 0)); 75 | //LafUtils.restoreComposite ( g2d, old ); 76 | } 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/action/IMActionHandler.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.action; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author ChenZhiHui <6208317@qq.com> 7 | * @create-time 2013-4-1 8 | */ 9 | @Documented 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Target(ElementType.METHOD) 12 | public @interface IMActionHandler { 13 | String name() default ""; 14 | 15 | String enabledProperty() default ""; 16 | 17 | String selectedProperty() default ""; 18 | 19 | @Retention(RetentionPolicy.RUNTIME) 20 | @Target(ElementType.PARAMETER) 21 | @interface Parameter { 22 | String value() default ""; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/action/IMActionHandlerProxy.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.action; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.ActionListener; 8 | import java.lang.reflect.Method; 9 | 10 | /** 11 | * Project : iqq-projects 12 | * Author : 承∮诺 < 6208317@qq.com > 13 | * Created : 14-5-11 14 | * License : Apache License 2.0 15 | */ 16 | public class IMActionHandlerProxy implements ActionListener { 17 | private static final Logger logger = LoggerFactory.getLogger(IMActionHandlerProxy.class.getName()); 18 | private Object proxyObject; 19 | private String actionName; 20 | private Method method; 21 | private Object[] params; 22 | 23 | public IMActionHandlerProxy(Object proxyObject, String actionName, Object... params) { 24 | this.proxyObject = proxyObject; 25 | this.actionName = actionName; 26 | this.params = params; 27 | 28 | for (Method m : proxyObject.getClass().getDeclaredMethods()) { 29 | if (m.isAnnotationPresent(IMActionHandler.class)) { 30 | IMActionHandler handler = m 31 | .getAnnotation(IMActionHandler.class); 32 | if (!handler.name().isEmpty() && actionName.equals(handler.name())) { 33 | this.method = m; 34 | } else if (handler.name().isEmpty() && actionName.equals(m.getName())) { 35 | this.method = m; 36 | } 37 | if (!m.isAccessible()) { 38 | m.setAccessible(true); 39 | } 40 | } 41 | } 42 | } 43 | 44 | @Override 45 | public void actionPerformed(ActionEvent evt) { 46 | if (method == null) { 47 | throw new IllegalArgumentException("invoke IMActionHandlerProxy Error!! no method: " + actionName); 48 | } 49 | try { 50 | if (method.getParameterTypes().length == 0) { 51 | method.invoke(proxyObject); 52 | return; 53 | } 54 | Class[] types = method.getParameterTypes(); 55 | if (types[0].equals(ActionEvent.class)) { 56 | if (types.length == 1) { 57 | method.invoke(proxyObject, evt); 58 | } else { 59 | Object[] ps = new Object[params.length + 1]; 60 | ps[0] = evt; 61 | for (int i = 1; i < params.length + 1; i++) { 62 | ps[i] = params[i - 1]; 63 | } 64 | method.invoke(proxyObject, ps); 65 | } 66 | } else { 67 | method.invoke(proxyObject, params); 68 | } 69 | } catch (Throwable e) { 70 | logger.warn("invoke IMActionHandlerProxy Error!!", e); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/border/RoundBorder.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.border; 2 | 3 | import javax.swing.border.Border; 4 | import java.awt.*; 5 | 6 | /** 7 | * Project : iqq-projects 8 | * Author : 承∮诺 < 6208317@qq.com > 9 | * Created : 14-5-11 10 | * License : Apache License 2.0 11 | */ 12 | public class RoundBorder implements Border { 13 | @Override 14 | public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { 15 | final Graphics2D g2d = (Graphics2D) g; 16 | g2d.setPaint(new Color(160, 160, 160)); 17 | g2d.drawRoundRect(x, y, width, height, 10, 10); 18 | } 19 | 20 | @Override 21 | public Insets getBorderInsets(Component c) { 22 | return new Insets(5, 5, 5, 5); 23 | } 24 | 25 | @Override 26 | public boolean isBorderOpaque() { 27 | return true; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/border/ShadeBorder.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.border; 2 | 3 | import javax.swing.border.Border; 4 | import java.awt.*; 5 | 6 | /** 7 | * Project : iqq-projects 8 | * Author : 承∮诺 < 6208317@qq.com > 9 | * Created : 14-5-11 10 | * License : Apache License 2.0 11 | */ 12 | public class ShadeBorder implements Border { 13 | @Override 14 | public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { 15 | final Graphics2D g2d = (Graphics2D) g; 16 | g2d.setPaint(new Color(160, 160, 160, 60)); 17 | g2d.fillRoundRect(x, y, width, height, 10, 10); 18 | } 19 | 20 | @Override 21 | public Insets getBorderInsets(Component c) { 22 | return new Insets(10, 10, 10, 10); 23 | } 24 | 25 | @Override 26 | public boolean isBorderOpaque() { 27 | return true; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/border/TabContentPanelBorder.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.border; 2 | 3 | import org.sexydock.tabs.jhrome.JhromeContentPanelBorder; 4 | 5 | import java.awt.*; 6 | import java.awt.geom.Path2D; 7 | 8 | /** 9 | * Project : iqq-projects 10 | * Author : 承∮诺 < 6208317@qq.com > 11 | * Created : 14-5-13 12 | * License : Apache License 2.0 13 | */ 14 | public class TabContentPanelBorder extends JhromeContentPanelBorder { 15 | int roundness = 3; 16 | int thickness = 0; 17 | Color outlineColor = new Color(55, 55, 55, 120); 18 | Color backgroundColor = new Color(255, 255, 255, 0); 19 | 20 | /* 21 | * (non-Javadoc) 22 | * 23 | * @see javax.swing.border.Border#paintBorder(java.awt.Component, java.awt.Graphics, int, int, int, int) 24 | */ 25 | @Override 26 | public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { 27 | Graphics2D g2 = (Graphics2D) g; 28 | 29 | int inset = Math.max(thickness - 1, 0); 30 | 31 | Path2D path = new Path2D.Double(); 32 | path.moveTo(x + inset, y + height - inset - inset); 33 | path.lineTo(x + inset, y + inset + roundness); 34 | path.curveTo(x + inset, y + inset, x + inset, y + inset, x + inset + roundness, y + inset); 35 | path.lineTo(x + width - roundness - inset - inset, y + inset); 36 | path.curveTo(x + width - inset - inset, y + inset, x + width - inset - inset, y + inset, x + width - inset - inset, y + inset + roundness); 37 | path.lineTo(x + width - inset - inset, y + height - inset - inset); 38 | path.closePath(); 39 | 40 | Stroke prevStroke = g2.getStroke(); 41 | Paint prevPaint = g2.getPaint(); 42 | Object prevAntialias = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING); 43 | g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 44 | 45 | g2.setStroke(new BasicStroke(thickness)); 46 | g2.setColor(outlineColor); 47 | g2.draw(path); 48 | 49 | g2.setColor(backgroundColor); 50 | g2.fill(path); 51 | 52 | g2.setStroke(prevStroke); 53 | g2.setPaint(prevPaint); 54 | g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, prevAntialias); 55 | } 56 | 57 | @Override 58 | public Insets getBorderInsets(Component c) { 59 | return new Insets(roundness + thickness, roundness + thickness, roundness + thickness, roundness + thickness); 60 | } 61 | 62 | @Override 63 | public boolean isBorderOpaque() { 64 | // TODO Auto-generated method stub 65 | return false; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/dialog/TipDialog.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.dialog; 2 | 3 | import com.alee.extended.panel.CenterPanel; 4 | import com.alee.extended.panel.VerticalPanel; 5 | import com.alee.laf.button.WebButton; 6 | import com.alee.laf.panel.WebPanel; 7 | import com.alee.laf.rootpane.WebFrame; 8 | import com.alee.laf.text.WebTextArea; 9 | import iqq.app.core.service.SkinService; 10 | import iqq.app.ui.IMContentPane; 11 | import iqq.app.ui.IMDialog; 12 | import iqq.app.ui.IMFrame; 13 | import iqq.app.ui.component.TitleComponent; 14 | import iqq.app.util.UIUtils; 15 | 16 | import javax.swing.*; 17 | import java.awt.*; 18 | import java.awt.event.ActionEvent; 19 | import java.awt.event.ActionListener; 20 | 21 | /** 22 | * Created by Tony on 5/22/15. 23 | */ 24 | public class TipDialog extends IMDialog { 25 | private IMContentPane contentPane = new IMContentPane(); 26 | private WebTextArea messageTxt; 27 | 28 | public TipDialog(IMFrame owner) { 29 | super(owner); 30 | 31 | initUI(); 32 | initContent(); 33 | } 34 | 35 | private void initUI() { 36 | setTitle("提示"); 37 | setModal(true); 38 | setDefaultCloseOperation(WebFrame.DISPOSE_ON_CLOSE); 39 | setAlwaysOnTop(true); 40 | setPreferredSize(new Dimension(240, 160)); // 首选大小 41 | setLocation(UIUtils.getLocationForCenter(owner)); 42 | pack(); 43 | } 44 | 45 | @Override 46 | public void installSkin(SkinService skinService) { 47 | super.installSkin(skinService); 48 | // 背景 49 | contentPane.setPainter(skinService.getPainterByKey("skin/background")); 50 | setIconImage(getSkinService().getIconByKey("skin/skinIcon").getImage()); 51 | } 52 | 53 | private void initContent() { 54 | contentPane.add(headerPanel(), BorderLayout.NORTH); 55 | contentPane.add(contentPanel(), BorderLayout.CENTER); 56 | setIMContentPane(contentPane); 57 | } 58 | 59 | private WebPanel headerPanel() { 60 | WebPanel headerPanel = new WebPanel(); 61 | headerPanel.setOpaque(false); 62 | TitleComponent titleComponent = new TitleComponent(owner); 63 | titleComponent.setShowSettingButton(false); 64 | titleComponent.setShowMaximizeButton(false); 65 | titleComponent.setShowSkinButton(false); 66 | titleComponent.setShowMinimizeButton(false); 67 | headerPanel.add(titleComponent, BorderLayout.NORTH); 68 | return headerPanel; 69 | } 70 | 71 | private WebPanel contentPanel() { 72 | WebPanel contentPanel = new WebPanel(); 73 | messageTxt = new WebTextArea(); 74 | messageTxt.setEditable(false); 75 | messageTxt.setLineWrap(true); 76 | messageTxt.setWrapStyleWord(true); 77 | messageTxt.setBackground(getBackground()); 78 | messageTxt.setAlignmentX(SwingConstants.CENTER); 79 | messageTxt.setMargin(20); 80 | WebButton okBtn = new WebButton("确定"); 81 | okBtn.setPreferredWidth(30); 82 | okBtn.addActionListener(new ActionListener() { 83 | @Override 84 | public void actionPerformed(ActionEvent e) { 85 | dispose(); 86 | } 87 | }); 88 | contentPanel.add(new CenterPanel(messageTxt), BorderLayout.CENTER); 89 | contentPanel.add(okBtn, BorderLayout.PAGE_END); 90 | return contentPanel; 91 | } 92 | 93 | /** 94 | * 设置提示信息 95 | * 96 | * @param text 97 | */ 98 | public void setMessage(String text) { 99 | messageTxt.setText(text); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/event/UIEvent.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.event; 2 | /* 3 | * Licensed to the Apache Software Foundation (ASF) under one or more 4 | * contributor license agreements. See the NOTICE file distributed with 5 | * this work for additional information regarding copyright ownership. 6 | * The ASF licenses this file to You under the Apache License, Version 2.0 7 | * (the "License"); you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import iqq.api.common.EventBase; 20 | 21 | import java.io.Serializable; 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | 25 | /** 26 | * Project : iqq 27 | * Author : solosky < solosky772@qq.com > 28 | * Created : 5/3/14 29 | * License : Apache License 2.0 30 | */ 31 | public class UIEvent extends EventBase implements Serializable { 32 | /** 33 | * 事件ID,定义在IMEventID 34 | */ 35 | private UIEventType type; 36 | 37 | public UIEvent(UIEventType type) { 38 | this.type = type; 39 | } 40 | 41 | public UIEvent() { 42 | } 43 | 44 | public UIEvent(UIEventType type, Object target) { 45 | this.type = type; 46 | this.target = target; 47 | } 48 | 49 | public UIEventType getType() { 50 | return type; 51 | } 52 | 53 | public void setType(UIEventType type) { 54 | this.type = type; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/event/UIEventDispatcher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.action 21 | * File : IMEventHandlerProxy.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-3-16 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.ui.event; 27 | 28 | import org.slf4j.Logger; 29 | import org.slf4j.LoggerFactory; 30 | 31 | import java.lang.reflect.Method; 32 | import java.util.HashMap; 33 | import java.util.Map; 34 | 35 | /** 36 | * 使用这个类简化事件的注册,分发 37 | * 只需在被代理的类使用@IMEventHandler注解需要处理的事件类型即可 38 | * 39 | * @author solosky 40 | */ 41 | public class UIEventDispatcher implements UIEventListener { 42 | private static final Logger LOG = LoggerFactory.getLogger(UIEventDispatcher.class); 43 | private Map methodMap = new HashMap(); 44 | private Object target; 45 | 46 | public UIEventDispatcher(Object target) { 47 | this.target = target; 48 | for (Method m : target.getClass().getDeclaredMethods()) { 49 | if (m.isAnnotationPresent(UIEventHandler.class)) { 50 | UIEventHandler handler = m.getAnnotation(UIEventHandler.class); 51 | this.methodMap.put(handler.value(), m); 52 | if (!m.isAccessible()) { 53 | m.setAccessible(true); 54 | } 55 | } 56 | } 57 | for (Method m : target.getClass().getMethods()) { 58 | if (m.isAnnotationPresent(UIEventHandler.class)) { 59 | UIEventHandler handler = m.getAnnotation(UIEventHandler.class); 60 | this.methodMap.put(handler.value(), m); 61 | if (!m.isAccessible()) { 62 | m.setAccessible(true); 63 | } 64 | } 65 | } 66 | } 67 | 68 | public UIEventType[] getEventTypes() { 69 | return methodMap.keySet().toArray(new UIEventType[]{}); 70 | } 71 | 72 | @Override 73 | public void onUIEvent(UIEvent imEvent) { 74 | Method m = methodMap.get(imEvent.getType()); 75 | if (m != null) { 76 | try { 77 | m.invoke(target, imEvent); 78 | } catch (Throwable e) { 79 | LOG.warn("invoke UIEventHandler Error!! {}.{}(..)", getClass(), m.getName(), e); 80 | } 81 | } else { 82 | LOG.warn("UIEventHandler Not Found!! imEvent = {}", imEvent); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/event/UIEventHandler.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.event; /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | /** 24 | * 事件处理注解,如果在方法上写上了这个注解,则说明此方法处理对应的消息 25 | *

26 | * Project : iqq 27 | * Author : solosky < solosky772@qq.com > 28 | * Created : 4/13/14 29 | * License : Apache License 2.0 30 | */ 31 | @Target(ElementType.METHOD) 32 | @Retention(RetentionPolicy.RUNTIME) 33 | public @interface UIEventHandler { 34 | public UIEventType value(); 35 | } 36 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/event/UIEventListener.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.event; 2 | 3 | /** 4 | * IM事件监听器 5 | */ 6 | public interface UIEventListener { 7 | /** 8 | * 触发事件回掉 9 | * 10 | * @param imEvent 11 | */ 12 | public void onUIEvent(UIEvent imEvent); 13 | } 14 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/event/args/LoginInfoParam.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.event.args; 2 | /* 3 | * Licensed to the Apache Software Foundation (ASF) under one or more 4 | * contributor license agreements. See the NOTICE file distributed with 5 | * this work for additional information regarding copyright ownership. 6 | * The ASF licenses this file to You under the Apache License, Version 2.0 7 | * (the "License"); you may not use this file except in compliance with 8 | * the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import iqq.api.bean.IMStatus; 20 | 21 | import java.io.Serializable; 22 | 23 | /** 24 | * Project : iqq 25 | * Author : solosky < solosky772@qq.com > 26 | * Created : 6/14/14 27 | * License : Apache License 2.0 28 | */ 29 | public class LoginInfoParam implements Serializable { 30 | private String username; 31 | private String password; 32 | private IMStatus status; 33 | private boolean remPwd; 34 | 35 | public String getUsername() { 36 | return username; 37 | } 38 | 39 | public void setUsername(String username) { 40 | this.username = username; 41 | } 42 | 43 | public String getPassword() { 44 | return password; 45 | } 46 | 47 | public void setPassword(String password) { 48 | this.password = password; 49 | } 50 | 51 | public IMStatus getStatus() { 52 | return status; 53 | } 54 | 55 | public void setStatus(IMStatus status) { 56 | this.status = status; 57 | } 58 | 59 | public boolean isRemPwd() { 60 | return remPwd; 61 | } 62 | 63 | public void setRemPwd(boolean remPwd) { 64 | this.remPwd = remPwd; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/ChatPane.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.frame.panel.chat; 2 | 3 | import iqq.app.core.service.SkinService; 4 | import iqq.app.ui.IMContentPane; 5 | import iqq.app.ui.border.TabContentPanelBorder; 6 | import iqq.app.ui.component.TitleComponent; 7 | import iqq.app.ui.frame.ChatFrame; 8 | import org.sexydock.tabs.jhrome.JhromeTabBorderAttributes; 9 | import org.sexydock.tabs.jhrome.JhromeTabbedPaneUI; 10 | 11 | import javax.swing.*; 12 | import java.awt.*; 13 | 14 | /** 15 | * Project : iqq-projects 16 | * Author : 承∮诺 < 6208317@qq.com > 17 | * Created : 14-5-10 18 | * License : Apache License 2.0 19 | */ 20 | public class ChatPane extends IMContentPane { 21 | 22 | private ChatFrame frame; 23 | private JTabbedPane tabbedPane; 24 | private JButton settingButton; 25 | 26 | public ChatPane(ChatFrame chatFrame) { 27 | super(); 28 | 29 | frame = chatFrame; 30 | 31 | initTabbedPane(); 32 | } 33 | 34 | public JTabbedPane getTabbedPane() { 35 | return tabbedPane; 36 | } 37 | 38 | private void initTabbedPane() { 39 | TitleComponent titleComponent = new TitleComponent(frame); 40 | titleComponent.setShowSkinButton(false); 41 | titleComponent.setShowSettingButton(false); 42 | //titleComponent.setShowTitle(false); 43 | add(titleComponent, BorderLayout.NORTH); 44 | 45 | JhromeTabBorderAttributes.SELECTED_BORDER.topColor = new Color(255, 255, 255, 120); 46 | JhromeTabBorderAttributes.SELECTED_BORDER.bottomColor = new Color(255, 255, 255, 0); 47 | JhromeTabBorderAttributes.SELECTED_BORDER.shadowColor = new Color(55, 55, 55, 50); 48 | JhromeTabBorderAttributes.SELECTED_BORDER.outlineColor = new Color(55, 55, 55, 100); 49 | JhromeTabBorderAttributes.UNSELECTED_BORDER.topColor = new Color(255, 255, 255, 40); 50 | JhromeTabBorderAttributes.UNSELECTED_BORDER.bottomColor = new Color(255, 255, 255, 0); 51 | JhromeTabBorderAttributes.UNSELECTED_BORDER.shadowColor = new Color(55, 55, 55, 20); 52 | JhromeTabBorderAttributes.UNSELECTED_BORDER.outlineColor = new Color(55, 55, 55, 100); 53 | JhromeTabBorderAttributes.UNSELECTED_ROLLOVER_BORDER.topColor = new Color(255, 255, 255, 160); 54 | JhromeTabBorderAttributes.UNSELECTED_ROLLOVER_BORDER.bottomColor = new Color(255, 255, 255, 50); 55 | JhromeTabbedPaneUI ui = new JhromeTabbedPaneUI(); 56 | tabbedPane = new JTabbedPane(); 57 | tabbedPane.setUI(ui); 58 | tabbedPane.setOpaque(false); 59 | tabbedPane.putClientProperty(JhromeTabbedPaneUI.TAB_CLOSE_BUTTONS_VISIBLE, true); 60 | tabbedPane.putClientProperty(JhromeTabbedPaneUI.NEW_TAB_BUTTON_VISIBLE, true); 61 | tabbedPane.putClientProperty(JhromeTabbedPaneUI.CONTENT_PANEL_BORDER, new TabContentPanelBorder()); 62 | settingButton = ui.getNewTabButton(); 63 | add(tabbedPane, BorderLayout.CENTER); 64 | } 65 | 66 | @Override 67 | public void installSkin(SkinService skinService) { 68 | super.installSkin(skinService); 69 | // 背景 70 | this.setPainter(skinService.getPainterByKey("skin/background")); 71 | settingButton.setIcon(skinService.getIconByKey("chat/settingIcon", 14, 14)); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/RoomPanel.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.frame.panel.chat; 2 | 3 | import iqq.api.bean.IMRoom; 4 | 5 | /** 6 | * Project : iqq-projects 7 | * Author : 承∮诺 < 6208317@qq.com > 8 | * Created : 14-5-11 9 | * License : Apache License 2.0 10 | */ 11 | public class RoomPanel extends BasicPanel { 12 | 13 | public RoomPanel(IMRoom entity) { 14 | super(entity); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/UserPanel.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.frame.panel.chat; 2 | 3 | import com.alee.laf.button.WebButton; 4 | import com.alee.laf.toolbar.WebToolBar; 5 | import iqq.api.bean.IMMsg; 6 | import iqq.api.bean.IMUser; 7 | import iqq.api.bean.content.IMContentItem; 8 | import iqq.api.bean.content.IMTextItem; 9 | import iqq.app.core.service.SkinService; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Date; 13 | 14 | /** 15 | * Project : iqq-projects 16 | * Author : 承∮诺 < 6208317@qq.com > 17 | * Created : 14-5-11 18 | * License : Apache License 2.0 19 | */ 20 | public class UserPanel extends BasicPanel { 21 | 22 | protected WebButton shakeBtn; 23 | 24 | public UserPanel(IMUser entity) { 25 | super(entity); 26 | 27 | // test(); 28 | } 29 | 30 | private void test() { 31 | IMMsg msg = new IMMsg(); 32 | msg.setSender((IMUser) entity); 33 | java.util.List contents = new ArrayList(); 34 | IMTextItem text = new IMTextItem("test content..."); 35 | contents.add(text); 36 | msg.setContents(contents); 37 | msg.setDate(new Date()); 38 | msg.setState(IMMsg.State.READ); 39 | showMsg(msg); 40 | showMsg(msg); 41 | showMsg(msg); 42 | showMsg(msg); 43 | showMsg(msg); 44 | } 45 | 46 | public IMUser getUser() { 47 | return (IMUser) this.entity; 48 | } 49 | 50 | @Override 51 | protected void initInputToolbar(WebToolBar inputToolbar) { 52 | super.initInputToolbar(inputToolbar); 53 | 54 | shakeBtn = new WebButton(); 55 | 56 | setInputButtonStyle(shakeBtn); 57 | 58 | // 震动 59 | inputToolbar.add(3, shakeBtn); 60 | } 61 | 62 | @Override 63 | public void installSkin(SkinService skinService) { 64 | super.installSkin(skinService); 65 | 66 | shakeBtn.setIcon(skinService.getIconByKey("chat/toolbar/shake")); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/msg/MsgGroupPanel.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.frame.panel.chat.msg; 2 | 3 | import com.alee.extended.panel.GroupPanel; 4 | import iqq.api.bean.IMMsg; 5 | import iqq.api.bean.IMUser; 6 | 7 | import java.awt.*; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * @author ChenZhiHui <6208317@qq.com> 13 | * @create-time 2013-3-24 14 | */ 15 | public class MsgGroupPanel extends GroupPanel { 16 | private static final long serialVersionUID = -3757572461881253014L; 17 | 18 | public MsgGroupPanel() { 19 | super(false); 20 | setOpaque(true); 21 | setBackground(new Color(245, 245, 245)); 22 | } 23 | 24 | public void updateMsg(IMMsg msg) { 25 | for (Component comp : getComponents()) { 26 | if (comp instanceof MsgPane) { 27 | MsgPane pane = (MsgPane) comp; 28 | IMMsg cur = pane.getMsg(); 29 | long msgId = cur.getId(); 30 | if (msgId == msg.getId()) { 31 | pane.invalidate(); 32 | return; 33 | } 34 | } 35 | } 36 | } 37 | 38 | public void updateUser(IMUser user) { 39 | for (Component comp : getComponents()) { 40 | if (comp instanceof MsgPane) { 41 | MsgPane pane = (MsgPane) comp; 42 | IMMsg cur = pane.getMsg(); 43 | IMUser sender = cur.getSender(); 44 | if (user.equals(sender)) { 45 | pane.invalidate(); 46 | } 47 | } 48 | } 49 | } 50 | 51 | public List getMsgList() { 52 | List list = new ArrayList(); 53 | for (Component comp : getComponents()) { 54 | if (comp instanceof MsgPane) { 55 | MsgPane pane = (MsgPane) comp; 56 | list.add(pane.getMsg()); 57 | } 58 | } 59 | return list; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/picloader/PicLoadListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.ui.content.chat.picloader 21 | * File : PicLoadListener.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-4-20 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.ui.frame.panel.chat.picloader; 27 | 28 | import java.awt.*; 29 | 30 | /** 31 | * 32 | * 图片加载监听器,UI通过这个监听器获得图片加载进度和结果 33 | * 34 | * @author solosky 35 | * 36 | */ 37 | public interface PicLoadListener { 38 | public void onProgress(long current, long total); 39 | 40 | public void onError(Throwable t); 41 | 42 | public void onSuccess(Image image); 43 | } 44 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/picloader/PicLoadState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.ui.content.chat.picloader 21 | * File : PicLoadState.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-4-20 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.ui.frame.panel.chat.picloader; 27 | 28 | /** 29 | * 30 | * 加载状态 31 | * 32 | * @author solosky 33 | * 34 | */ 35 | public enum PicLoadState { 36 | PENDING, 37 | SUCCESS, 38 | ERROR, 39 | LOADING, 40 | UPLOADING 41 | } 42 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/picloader/PicLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.ui.content.chat.picloader 21 | * File : PicLoader.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-4-20 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.ui.frame.panel.chat.picloader; 27 | 28 | import iqq.api.bean.content.IMContentItem; 29 | 30 | import java.awt.*; 31 | import java.io.Serializable; 32 | 33 | /** 34 | * 35 | * 图片加载或者上传接口 36 | * 可以是加载网络上的图片,也可以是加载本地图片 37 | * 需序列话保存在本地,实现是注意考虑序列号问题 38 | * 39 | * @author solosky 40 | * 41 | */ 42 | public interface PicLoader extends Serializable { 43 | public void loadPic(); 44 | 45 | public void sendToServer(); 46 | 47 | public void addListener(PicLoadListener listener); 48 | 49 | public void removeListener(PicLoadListener listener); 50 | 51 | public IMContentItem getContentItem(); 52 | 53 | public PicLoadState getState(); 54 | 55 | public Image getPic(); 56 | } 57 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/picloader/PicLoaderFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.ui.content.chat.picloader 21 | * File : PicLoaderFactory.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-4-20 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.ui.frame.panel.chat.picloader; 27 | 28 | import iqq.api.bean.IMAccount; 29 | import iqq.api.bean.IMMsg; 30 | import iqq.api.bean.content.IMContentItem; 31 | import iqq.api.bean.content.IMPictureItem; 32 | 33 | import java.io.File; 34 | 35 | /** 36 | * 37 | * 工厂类,根据QQMsg和ContentItem来创建Loader 38 | * 39 | * @author solosky 40 | * 41 | */ 42 | public class PicLoaderFactory { 43 | /*** 44 | * 通过消息中的一个对象来创建PicLoader 45 | * @param item CFaceItem或OffPicItem, 其他抛出异常 IllegalArgumentException 46 | * @param msg 接收到的QQ消息对象 47 | * @return 48 | */ 49 | public static PicLoader createLoader(IMContentItem item, IMMsg msg) { 50 | if (item instanceof UserPicLoader) { 51 | return new UserPicLoader((IMPictureItem) item, msg.getSender()); 52 | } 53 | throw new IllegalArgumentException("invalid content item:" + item); 54 | } 55 | 56 | /*** 57 | * 通过要发送消息的对象来创建对应的PicLoader 58 | * @param picFile 图片文件 59 | * @param target 发送对象,QQUser, QQGroup, QQDiscuz, 其他抛出异常 IllegalArgumentException 60 | * @param self 用户自己对象 61 | * @return 62 | */ 63 | public static PicLoader createLoader(File picFile, Object target, IMAccount self) { 64 | 65 | throw new IllegalArgumentException("invalid target:" + target); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/picloader/UserPicLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.ui.content.chat.picloader 21 | * File : CFacePicLoader.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-4-20 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.ui.frame.panel.chat.picloader; 27 | 28 | import iqq.api.bean.IMEntity; 29 | import iqq.api.bean.content.IMPictureItem; 30 | import iqq.api.event.IMEvent; 31 | 32 | import java.io.File; 33 | 34 | /** 35 | * 36 | * 用户图片,其实也是CFace,但获取的地址和方式不同 37 | * 38 | * @author solosky 39 | * 40 | */ 41 | public class UserPicLoader extends AbstractPicLoader { 42 | private static final long serialVersionUID = 1L; 43 | private File file; 44 | private IMEntity owner; 45 | 46 | public UserPicLoader(IMPictureItem item, IMEntity owner) { 47 | this.file = item.getFile(); 48 | this.owner = owner; 49 | } 50 | 51 | @Override 52 | protected void doLoadFromServer() throws Exception { 53 | 54 | 55 | } 56 | 57 | @Override 58 | protected void doSendToServer() throws Exception { 59 | throw new UnsupportedOperationException("not supported!!"); 60 | } 61 | 62 | @Override 63 | protected boolean isMyEvent(IMEvent event) { 64 | return false; 65 | } 66 | 67 | 68 | @Override 69 | public void sendToServer() { 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/rich/UIBasicItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.ui.content.chat.rich 21 | * File : AbstractItem.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-4-8 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.ui.frame.panel.chat.rich; 27 | 28 | import com.alee.extended.panel.GroupPanel; 29 | 30 | /** 31 | * 32 | * 抽象的富文本对象,可以作为子类继承,实现了保存IMContext的基本方法 33 | * 34 | * @author solosky 35 | * 36 | */ 37 | public abstract class UIBasicItem implements UIRichItem { 38 | private static final long serialVersionUID = 1L; 39 | 40 | protected static class UIBasicComponent extends GroupPanel implements UIRichComponent { 41 | private static final long serialVersionUID = 1L; 42 | private UIRichItem richItem; 43 | 44 | public UIBasicComponent(UIRichItem richItem) { 45 | this.richItem = richItem; 46 | } 47 | 48 | @Override 49 | public UIRichItem getRichItem() { 50 | return richItem; 51 | } 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/rich/UIFaceItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.ui.content.chat.rich 21 | * File : UIFaceItem.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-4-8 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.ui.frame.panel.chat.rich; 27 | 28 | import javax.swing.*; 29 | 30 | /** 31 | * 32 | * 表情对象 33 | * 34 | * @author solosky 35 | * 36 | */ 37 | public class UIFaceItem extends UIBasicItem { 38 | private static final long serialVersionUID = 1L; 39 | private int faceId; 40 | 41 | public UIFaceItem(int faceId) { 42 | this.faceId = faceId; 43 | } 44 | 45 | public int getFaceId() { 46 | return faceId; 47 | } 48 | 49 | @Override 50 | public void insertTo(JTextPane pane) throws Exception { 51 | //FaceIcon icon = FaceWindow.getFaceIconById(faceId); 52 | //pane.insertComponent(new UIFaceComponent(icon)); 53 | } 54 | 55 | private class UIFaceComponent extends JLabel implements UIRichComponent { 56 | /* 57 | UIFaceComponent(FaceIcon icon){ 58 | super(); 59 | setIcon(icon.getIcon()); 60 | } 61 | */ 62 | @Override 63 | public UIRichItem getRichItem() { 64 | return UIFaceItem.this; 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/rich/UILinkItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.ui.content.chat.rich 21 | * File : UILinkItem.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-4-9 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.ui.frame.panel.chat.rich; 27 | 28 | import javax.swing.*; 29 | import javax.swing.text.Document; 30 | import javax.swing.text.SimpleAttributeSet; 31 | import javax.swing.text.StyleConstants; 32 | import javax.swing.text.html.HTML; 33 | import java.awt.*; 34 | 35 | /** 36 | * 37 | * 超链接组件 38 | * 39 | * @author solosky 40 | * 41 | */ 42 | public class UILinkItem extends UIBasicItem { 43 | private static final long serialVersionUID = 1L; 44 | private String link; 45 | private transient Action action; 46 | 47 | public UILinkItem(String link) { 48 | this.link = link; 49 | } 50 | 51 | public UILinkItem(String link, Action action) { 52 | this.link = link; 53 | this.action = action; 54 | } 55 | 56 | @Override 57 | public void insertTo(final JTextPane pane) throws Exception { 58 | Document doc = pane.getDocument(); 59 | SimpleAttributeSet attrs = new SimpleAttributeSet(); 60 | StyleConstants.setUnderline(attrs, true); 61 | StyleConstants.setForeground(attrs, Color.BLUE);// unvisited color 62 | // StyleConstants.setFontSize(null, 13); 63 | attrs.addAttribute(HTML.Attribute.HREF, link); 64 | if (action != null) { 65 | attrs.addAttribute("action", action); 66 | attrs.addAttribute("self", this); 67 | } 68 | doc.insertString(doc.getLength(), link, attrs); 69 | } 70 | 71 | public String getLink() { 72 | return link; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/rich/UIRichComponent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.ui.content.chat.rich 21 | * File : UIRichComponent.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-4-9 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.ui.frame.panel.chat.rich; 27 | 28 | /** 29 | * 30 | * UI图形化组件,是具体加入RichPane的图形组件 31 | * 所有加入RichPane的图形组件都需要实现这个接口,便于获得UIRichItem对象 32 | * 33 | * @author solosky 34 | * 35 | */ 36 | public interface UIRichComponent { 37 | public UIRichItem getRichItem(); 38 | } 39 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/rich/UIRichItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.ui.content.chat.rich 21 | * File : RichItem.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-4-8 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.ui.frame.panel.chat.rich; 27 | 28 | import javax.swing.*; 29 | import java.io.Serializable; 30 | 31 | /** 32 | * 33 | * 富文本编辑器内容对象 34 | * 注意实现此接口需要考虑到序列化的问题 35 | * 36 | * @author solosky 37 | * 38 | */ 39 | public interface UIRichItem extends Serializable { 40 | 41 | /*** 42 | * 把当前对象加入到TextPane里面 43 | * @param pane 44 | */ 45 | public void insertTo(JTextPane pane) throws Exception; 46 | } 47 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/rich/UISkinPicItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.ui.content.chat.rich 21 | * File : UIResPicItem.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-4-9 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.ui.frame.panel.chat.rich; 27 | 28 | 29 | import iqq.app.core.context.IMContext; 30 | import iqq.app.core.service.SkinService; 31 | import iqq.app.core.service.impl.SkinServiceImpl; 32 | 33 | import javax.swing.*; 34 | 35 | /** 36 | * 37 | * 插入程序皮肤本地资源 38 | * 通常这些图片都较小,并且都有缓存,直接添加即可 39 | * 40 | * @author solosky 41 | * 42 | */ 43 | public class UISkinPicItem extends UIBasicItem { 44 | private static final long serialVersionUID = 1L; 45 | private String picName; 46 | 47 | public UISkinPicItem(String picName) { 48 | this.picName = picName; 49 | } 50 | 51 | @Override 52 | public void insertTo(JTextPane pane) throws Exception { 53 | SkinService skins = IMContext.getBean(SkinServiceImpl.class); 54 | ImageIcon pic = skins.getIconByKey(picName); 55 | pane.insertComponent(new UISkinComponent(pic)); 56 | } 57 | 58 | private class UISkinComponent extends JLabel implements UIRichComponent { 59 | private static final long serialVersionUID = 1L; 60 | 61 | UISkinComponent(ImageIcon pic) { 62 | super(); 63 | setIcon(pic); 64 | } 65 | 66 | @Override 67 | public UIRichItem getRichItem() { 68 | return UISkinPicItem.this; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/chat/rich/UITextItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : IQQ_V2.1 20 | * Package : iqq.app.ui.content.chat.rich 21 | * File : TextItem.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-4-8 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.ui.frame.panel.chat.rich; 27 | 28 | import javax.swing.*; 29 | import javax.swing.text.StyledDocument; 30 | 31 | /** 32 | * 33 | * 普通文本对象 34 | * 35 | * @author solosky 36 | * 37 | */ 38 | public class UITextItem extends UIBasicItem { 39 | private static final long serialVersionUID = 1L; 40 | private String text; 41 | 42 | public UITextItem(String text) { 43 | this.text = text; 44 | } 45 | 46 | @Override 47 | public void insertTo(JTextPane pane) throws Exception { 48 | StyledDocument styledDocument = pane.getStyledDocument(); 49 | styledDocument.insertString(styledDocument.getLength(), text, pane.getCharacterAttributes()); 50 | } 51 | 52 | public String getText() { 53 | return text; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/login/LoginingPane.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.frame.panel.login; 2 | 3 | import iqq.app.ui.IMContentPane; 4 | 5 | /** 6 | * Project : iqq-projects 7 | * Author : 承∮诺 < 6208317@qq.com > 8 | * Created : 14-6-17 9 | * License : Apache License 2.0 10 | */ 11 | public class LoginingPane extends IMContentPane { 12 | 13 | public LoginingPane() { 14 | 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/main/FooterPanel.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.frame.panel.main; 2 | 3 | import com.alee.laf.button.WebButton; 4 | import com.alee.laf.toolbar.ToolbarStyle; 5 | import com.alee.laf.toolbar.WebToolBar; 6 | import iqq.app.core.context.IMContext; 7 | import iqq.app.core.service.SkinService; 8 | import iqq.app.ui.IMPanel; 9 | import iqq.app.ui.frame.MainFrame; 10 | import iqq.app.ui.manager.FrameManager; 11 | 12 | import java.awt.*; 13 | import java.awt.event.ActionEvent; 14 | import java.awt.event.ActionListener; 15 | 16 | /** 17 | * Project : iqq-projects 18 | * Author : 承∮诺 < 6208317@qq.com > 19 | * Created : 14-5-8 20 | * License : Apache License 2.0 21 | */ 22 | public class FooterPanel extends IMPanel { 23 | private MainFrame frame; 24 | private WebToolBar toolBar = new WebToolBar(); 25 | 26 | private WebButton add = new WebButton(); 27 | private WebButton mail = new WebButton(); 28 | private WebButton qzone = new WebButton(); 29 | private WebButton weibo = new WebButton(); 30 | private WebButton msg = new WebButton(); 31 | private WebButton setting = new WebButton(); 32 | 33 | 34 | public FooterPanel(MainFrame frame) { 35 | super(); 36 | this.frame = frame; 37 | 38 | initButtons(); 39 | initToolbar(); 40 | inttAction(); 41 | } 42 | 43 | private void inttAction() { 44 | add.addActionListener(new ActionListener() { 45 | @Override 46 | public void actionPerformed(ActionEvent e) { 47 | IMContext.getBean(FrameManager.class).showAddFriend(); 48 | } 49 | }); 50 | } 51 | 52 | private void initButtons() { 53 | 54 | } 55 | 56 | private void initToolbar() { 57 | toolBar.setFloatable(false); 58 | toolBar.setToolbarStyle(ToolbarStyle.attached); 59 | toolBar.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); 60 | toolBar.setTopBgColor(new Color(255, 255, 255, 130)); 61 | toolBar.setBottomBgColor(new Color(255, 255, 255, 130)); 62 | toolBar.setOpaque(false); 63 | 64 | toolBar.add(setting); 65 | toolBar.add(msg); 66 | toolBar.addSeparator(); 67 | toolBar.add(weibo); 68 | toolBar.add(qzone); 69 | toolBar.add(mail); 70 | toolBar.addSeparator(); 71 | toolBar.addToEnd(add); 72 | toolBar.setPreferredSize(new Dimension(-1, 26)); 73 | 74 | setButtonStyle(add, mail, qzone, weibo, msg, setting); 75 | 76 | add(toolBar); 77 | } 78 | 79 | protected void setButtonStyle(WebButton... bs) { 80 | for (WebButton b : bs) { 81 | b.setPreferredSize(new Dimension(40, 40)); 82 | b.setRound(2); 83 | b.setRolloverDecoratedOnly(true); 84 | b.setBackground(new Color(0, 0, 0, 0)); 85 | } 86 | } 87 | 88 | @Override 89 | public void installSkin(SkinService skinService) { 90 | super.installSkin(skinService); 91 | 92 | add.setIcon(skinService.getIconByKey("main/toolbar/add")); 93 | mail.setIcon(skinService.getIconByKey("main/toolbar/mail")); 94 | qzone.setIcon(skinService.getIconByKey("main/toolbar/qzone")); 95 | weibo.setIcon(skinService.getIconByKey("main/toolbar/weibo")); 96 | msg.setIcon(skinService.getIconByKey("main/toolbar/msg")); 97 | setting.setIcon(skinService.getIconByKey("main/toolbar/setting")); 98 | 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/frame/panel/main/MainPane.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.frame.panel.main; 2 | 3 | import iqq.app.core.service.SkinService; 4 | import iqq.app.ui.IMContentPane; 5 | import iqq.app.ui.frame.MainFrame; 6 | 7 | import java.awt.*; 8 | 9 | /** 10 | * Project : iqq-projects 11 | * Author : 承∮诺 < 6208317@qq.com > 12 | * Created : 14-5-5 13 | * License : Apache License 2.0 14 | */ 15 | public class MainPane extends IMContentPane { 16 | 17 | private MainFrame frame; 18 | private HeaderPanel headerPanel; 19 | private MiddlePanel middlePanel; 20 | private FooterPanel footerPanel; 21 | 22 | public MainPane(MainFrame mainFrame) { 23 | frame = mainFrame; 24 | 25 | headerPanel = new HeaderPanel(frame); 26 | middlePanel = new MiddlePanel(frame); 27 | footerPanel = new FooterPanel(frame); 28 | 29 | this.add(headerPanel, BorderLayout.NORTH); 30 | this.add(footerPanel, BorderLayout.SOUTH); 31 | this.add(middlePanel, BorderLayout.CENTER); 32 | } 33 | 34 | @Override 35 | public void installSkin(SkinService skinService) { 36 | // 背景 37 | this.setPainter(skinService.getPainterByKey("skin/background")); 38 | headerPanel.installSkin(skinService); 39 | middlePanel.installSkin(skinService); 40 | footerPanel.installSkin(skinService); 41 | } 42 | 43 | public HeaderPanel getHeaderPanel() { 44 | return headerPanel; 45 | } 46 | 47 | public void setHeaderPanel(HeaderPanel headerPanel) { 48 | this.headerPanel = headerPanel; 49 | } 50 | 51 | public MiddlePanel getMiddlePanel() { 52 | return middlePanel; 53 | } 54 | 55 | public void setMiddlePanel(MiddlePanel middlePanel) { 56 | this.middlePanel = middlePanel; 57 | } 58 | 59 | public FooterPanel getFooterPanel() { 60 | return footerPanel; 61 | } 62 | 63 | public void setFooterPanel(FooterPanel footerPanel) { 64 | this.footerPanel = footerPanel; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/manager/ChatManager.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.manager; 2 | 3 | import iqq.api.bean.IMBuddy; 4 | import iqq.api.bean.IMEntity; 5 | import iqq.api.bean.IMRoom; 6 | import iqq.api.bean.IMUser; 7 | import iqq.app.core.service.EventService; 8 | import iqq.app.ui.event.UIEvent; 9 | import iqq.app.ui.event.UIEventType; 10 | import iqq.app.ui.frame.ChatFrame; 11 | import iqq.app.ui.frame.panel.chat.BasicPanel; 12 | import iqq.app.ui.frame.panel.chat.RoomPanel; 13 | import iqq.app.ui.frame.panel.chat.UserPanel; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import org.springframework.stereotype.Component; 17 | 18 | import javax.annotation.Resource; 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | 22 | /** 23 | * 聊天窗口管理类,用于管理聊天对话 24 | *

25 | * Project : iqq-projects 26 | * Author : 承∮诺 < 6208317@qq.com > 27 | * Created : 14-5-12 28 | * License : Apache License 2.0 29 | */ 30 | @Component 31 | public class ChatManager { 32 | private final Logger LOG = LoggerFactory.getLogger(ChatManager.class); 33 | private ChatFrame chatFrame; 34 | private Map entityMap; 35 | @Resource 36 | private EventService eventService; 37 | 38 | public void addChat(IMEntity entity) { 39 | if (chatFrame == null) { 40 | chatFrame = new ChatFrame(); 41 | entityMap = new HashMap(); 42 | LOG.debug("创建了一个聊天窗口界面"); 43 | } 44 | 45 | if (!entityMap.containsKey(entity)) { 46 | if (entity instanceof IMUser) { 47 | // 用户对话 48 | UserPanel entityPanel = new UserPanel((IMUser) entity); 49 | entityMap.put(entity, entityPanel); 50 | chatFrame.addBuddyPane((IMBuddy) entity, entityPanel); 51 | } else if (entity instanceof IMRoom) { 52 | // 聊天室对话 53 | RoomPanel entityPanel = new RoomPanel((IMRoom) entity); 54 | entityMap.put(entity, entityPanel); 55 | chatFrame.addRoomPane((IMRoom) entity, entityPanel); 56 | } else { 57 | LOG.warn("未知的聊天实体类,无法打开聊天对话"); 58 | } 59 | } else { 60 | // 已经打开了对话,直接进行选中状态 61 | chatFrame.setSelectedChat(entityMap.get(entity)); 62 | } 63 | if (!chatFrame.isVisible()) { 64 | chatFrame.setVisible(true); 65 | } 66 | 67 | // 打开了聊天对话 68 | eventService.broadcast(new UIEvent(UIEventType.SHOW_CHAT, entity)); 69 | } 70 | 71 | /** 72 | * 删除了一个对话 73 | * 74 | * @param entity 75 | */ 76 | public void removeChat(IMEntity entity) { 77 | entityMap.remove(entity); 78 | 79 | // 关闭了聊天对话 80 | eventService.broadcast(new UIEvent(UIEventType.CLOSE_CHAT, entity)); 81 | } 82 | 83 | /** 84 | * 对话窗口已经关闭,进行清除处理 85 | */ 86 | public void clearChats() { 87 | for (IMEntity entity : entityMap.keySet()) { 88 | removeChat(entity); 89 | } 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/manager/FrameManager.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.manager; 2 | 3 | import iqq.api.bean.IMBuddy; 4 | import iqq.api.bean.IMEntity; 5 | import iqq.api.bean.IMUser; 6 | import iqq.app.ui.frame.*; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.Map; 10 | import java.util.Objects; 11 | 12 | /** 13 | * Created by Tony on 4/6/15. 14 | */ 15 | @Component 16 | public class FrameManager { 17 | 18 | private LoginFrame loginFrame = null; 19 | private VerifyFrame verifyFrame = null; 20 | private AddFriendFrame addFriendFrame = null; 21 | private ChooseCategoryFrame chooseCateFrame = null; 22 | private GetFriendRequestFrame getFriendRequestFrame = null; 23 | 24 | public void showLogin() { 25 | if (loginFrame == null) { 26 | loginFrame = new LoginFrame(); 27 | loginFrame.setVisible(true); 28 | } else if (!loginFrame.isVisible()) { 29 | loginFrame.setVisible(true); 30 | } 31 | } 32 | 33 | public void hideLogin() { 34 | if (loginFrame != null) { 35 | loginFrame.setVisible(false); 36 | } 37 | } 38 | 39 | public void disposeLogin() { 40 | if (loginFrame != null) { 41 | loginFrame.dispose(); 42 | loginFrame = null; 43 | } 44 | } 45 | 46 | public void showVerify() { 47 | if (verifyFrame == null) { 48 | verifyFrame = new VerifyFrame(); 49 | verifyFrame.setVisible(true); 50 | } else if (!verifyFrame.isVisible()) { 51 | verifyFrame.setVisible(true); 52 | } 53 | } 54 | 55 | public void hideVerify() { 56 | if (verifyFrame != null) { 57 | verifyFrame.setVisible(false); 58 | } 59 | } 60 | 61 | public void showAddFriend() { 62 | if (addFriendFrame == null) { 63 | addFriendFrame = new AddFriendFrame(); 64 | addFriendFrame.setVisible(true); 65 | } else if (!addFriendFrame.isVisible()) { 66 | addFriendFrame.setVisible(true); 67 | } 68 | } 69 | 70 | public void hideAddFriend() { 71 | if (addFriendFrame != null) { 72 | addFriendFrame.setVisible(false); 73 | } 74 | } 75 | 76 | public void showChooseCate(String id) { 77 | if (chooseCateFrame == null) { 78 | chooseCateFrame = new ChooseCategoryFrame(id); 79 | chooseCateFrame.setVisible(true); 80 | } else if (!chooseCateFrame.isVisible()) { 81 | chooseCateFrame.setVisible(true); 82 | } 83 | } 84 | 85 | public void hideChooseCate() { 86 | if (chooseCateFrame != null) { 87 | chooseCateFrame.setVisible(false); 88 | } 89 | } 90 | 91 | public void showGetFriendRequest(IMBuddy buddy, String buddyRequestId) { 92 | if (getFriendRequestFrame == null) { 93 | getFriendRequestFrame = new GetFriendRequestFrame(buddy, buddyRequestId); 94 | getFriendRequestFrame.setVisible(true); 95 | } else if (!getFriendRequestFrame.isVisible()) { 96 | getFriendRequestFrame.setVisible(true); 97 | } 98 | } 99 | 100 | public void hideGetFriendRequest() { 101 | if (getFriendRequestFrame != null) { 102 | getFriendRequestFrame.setVisible(false); 103 | } 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/manager/SkinManager.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.manager; 2 | 3 | import iqq.app.core.service.SkinService; 4 | import iqq.app.ui.skin.Skin; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.LinkedList; 10 | import java.util.List; 11 | 12 | /** 13 | * 皮肤管理器,可以更新新皮肤 14 | *

15 | * Project : iqq-projects 16 | * Author : 承∮诺 < 6208317@qq.com > 17 | * Created : 14-5-5 18 | * License : Apache License 2.0 19 | */ 20 | @Component 21 | public class SkinManager { 22 | private final Logger LOG = LoggerFactory.getLogger(SkinManager.class); 23 | private List skinList = new LinkedList(); 24 | 25 | /** 26 | * 注册皮肤管理 27 | * 28 | * @param skin 29 | */ 30 | public void register(Skin skin) { 31 | skinList.add(skin); 32 | LOG.debug("register " + skin.getClass().getName()); 33 | } 34 | 35 | /** 36 | * 取消注册皮肤管理,放弃持有引用,用来释放对象 37 | * 38 | * @param skin 39 | */ 40 | public void unregister(Skin skin) { 41 | skinList.remove(skin); 42 | LOG.debug("unregister " + skin.getClass().getName()); 43 | } 44 | 45 | /** 46 | * 安装所有皮肤,更新覆盖原来的 47 | * 48 | * @param skinService 49 | */ 50 | public void installAll(SkinService skinService) { 51 | for (Skin skin : skinList) { 52 | skin.installSkin(skinService); 53 | LOG.debug("install " + skin.getClass().getName()); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/renderer/BoddyTreeCellRenderer.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.renderer; 2 | 3 | import com.alee.laf.label.WebLabel; 4 | import iqq.app.ui.renderer.node.BuddyNode; 5 | import iqq.app.ui.renderer.node.CategoryNode; 6 | 7 | import javax.swing.*; 8 | import javax.swing.tree.TreeCellRenderer; 9 | import java.awt.*; 10 | 11 | /** 12 | * 好友树中单元显示 13 | *

14 | * Project : iqq-projects 15 | * Author : 承∮诺 < 6208317@qq.com > 16 | * Created : 14-5-8 17 | * License : Apache License 2.0 18 | */ 19 | public class BoddyTreeCellRenderer implements TreeCellRenderer { 20 | 21 | @Override 22 | public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { 23 | if (value instanceof CategoryNode) { 24 | CategoryNode cate = (CategoryNode) value; 25 | WebLabel cateLbl = cate.getView(); 26 | if (expanded) { 27 | cateLbl.setIcon(UIManager.getIcon("Tree.arrowDown")); 28 | } else { 29 | cateLbl.setIcon(UIManager.getIcon("Tree.arrowLeft")); 30 | } 31 | return cateLbl; 32 | } else if (value instanceof BuddyNode) { 33 | return ((BuddyNode) value).getView(); 34 | } 35 | return new WebLabel(value.toString()); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/renderer/CategoryComboxCellRenderer.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.renderer; 2 | 3 | import com.alee.laf.label.WebLabel; 4 | import iqq.api.bean.IMCategory; 5 | import iqq.api.bean.IMMsg; 6 | import iqq.app.ui.renderer.node.BuddyNode; 7 | import iqq.app.ui.renderer.node.CategoryNode; 8 | import javax.swing.*; 9 | import java.awt.*; 10 | 11 | public class CategoryComboxCellRenderer extends WebLabel implements ListCellRenderer { 12 | 13 | public CategoryComboxCellRenderer() { 14 | setOpaque(true); 15 | } 16 | 17 | public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 18 | IMCategory category = (IMCategory) value; 19 | setText(category.getName()); 20 | return this; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/renderer/RecentTreeCellRenderer.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.renderer; 2 | 3 | import com.alee.laf.label.WebLabel; 4 | import iqq.app.ui.renderer.node.BuddyNode; 5 | import iqq.app.ui.renderer.node.RoomNode; 6 | 7 | import javax.swing.*; 8 | import javax.swing.tree.TreeCellRenderer; 9 | import java.awt.*; 10 | 11 | /** 12 | * 最近列表树中单元显示 13 | *

14 | * Project : iqq-projects 15 | * Author : 承∮诺 < 6208317@qq.com > 16 | * Created : 14-5-9 17 | * License : Apache License 2.0 18 | */ 19 | public class RecentTreeCellRenderer implements TreeCellRenderer { 20 | public static int ICON_SIZE = 40; 21 | public static Insets LINE_MARGIN = new Insets(4, 15, 4, 4); 22 | 23 | @Override 24 | public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { 25 | if (value instanceof BuddyNode) { 26 | return ((BuddyNode) value).getView(); 27 | } else if (value instanceof RoomNode) { 28 | return ((RoomNode) value).getView(40, 40); 29 | } 30 | return new WebLabel(value.toString()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/renderer/RoomTreeCellRenderer.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.renderer; 2 | 3 | import com.alee.laf.label.WebLabel; 4 | import iqq.app.ui.renderer.node.CategoryNode; 5 | import iqq.app.ui.renderer.node.RoomNode; 6 | 7 | import javax.swing.*; 8 | import javax.swing.tree.TreeCellRenderer; 9 | import java.awt.*; 10 | 11 | /** 12 | * 聊天室树中单元显示 13 | *

14 | * Project : iqq-projects 15 | * Author : 承∮诺 < 6208317@qq.com > 16 | * Created : 14-5-9 17 | * License : Apache License 2.0 18 | */ 19 | public class RoomTreeCellRenderer implements TreeCellRenderer { 20 | @Override 21 | public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { 22 | if (value instanceof CategoryNode) { 23 | CategoryNode cate = (CategoryNode) value; 24 | WebLabel cateLbl = cate.getView(); 25 | if (expanded) { 26 | cateLbl.setIcon(UIManager.getIcon("Tree.arrowDown")); 27 | } else { 28 | cateLbl.setIcon(UIManager.getIcon("Tree.arrowLeft")); 29 | } 30 | return cateLbl; 31 | } else if (value instanceof RoomNode) { 32 | return ((RoomNode) value).getView(); 33 | } 34 | return new WebLabel(value.toString()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/renderer/node/BuddyNode.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.renderer.node; 2 | 3 | import com.alee.extended.image.WebDecoratedImage; 4 | import com.alee.extended.panel.CenterPanel; 5 | import com.alee.extended.panel.GroupPanel; 6 | import com.alee.laf.label.WebLabel; 7 | import com.alee.utils.ImageUtils; 8 | import iqq.api.bean.IMBuddy; 9 | import iqq.app.ui.IMPanel; 10 | import iqq.app.util.StatusUtils; 11 | import org.apache.commons.lang3.StringUtils; 12 | 13 | import java.awt.*; 14 | import java.awt.image.BufferedImage; 15 | 16 | /** 17 | * 好友显示节点 18 | *

19 | * Project : iqq-projects 20 | * Author : 承∮诺 < 6208317@qq.com > 21 | * Created : 14-5-10 22 | * License : Apache License 2.0 23 | */ 24 | public class BuddyNode extends EntityNode { 25 | private IMBuddy buddy; 26 | private IMPanel view = new IMPanel(); 27 | // 头像 28 | private BufferedImage avatar; 29 | private WebDecoratedImage avatarImage; 30 | // 昵称 31 | WebLabel nickLbl; 32 | WebLabel signLbl; 33 | 34 | public BuddyNode(IMBuddy buddy) { 35 | super(buddy); 36 | this.buddy = buddy; 37 | 38 | // 头像 39 | avatarImage = new WebDecoratedImage(); 40 | avatarImage.setShadeWidth(1); 41 | avatarImage.setRound(4); 42 | avatarImage.setDrawGlassLayer(false); 43 | 44 | // 昵称 45 | nickLbl = new WebLabel(); 46 | signLbl = new WebLabel(); 47 | nickLbl.setFontSize(14); 48 | signLbl.setFontSize(13); 49 | signLbl.setForeground(Color.GRAY); 50 | GroupPanel textGroup = new GroupPanel(0, false, nickLbl, signLbl); 51 | textGroup.setMargin(0, 5, 0, 5); 52 | 53 | view.add(avatarImage, BorderLayout.WEST); 54 | view.add(new CenterPanel(textGroup, false, true), BorderLayout.CENTER); 55 | view.setMargin(5); 56 | } 57 | 58 | public void setAvatar(BufferedImage avatar) { 59 | this.avatar = avatar; 60 | this.avatarImage.setIcon(ImageUtils.createPreviewIcon(StatusUtils.drawStatusFace(buddy.getStatus(), avatar), 45)); 61 | } 62 | 63 | public IMBuddy getBuddy() { 64 | return buddy; 65 | } 66 | 67 | public void setBuddy(IMBuddy buddy) { 68 | this.buddy = buddy; 69 | } 70 | 71 | /** 72 | * 这个方法特别频繁,一定要处理好 73 | * 74 | * @return 75 | */ 76 | public IMPanel getView() { 77 | if (avatar == null || avatar != buddy.getAvatarBuffered()) { 78 | setAvatar(buddy.getAvatarBuffered()); 79 | } 80 | if (!StringUtils.equals(nickLbl.getText(), buddy.getNick())) { 81 | nickLbl.setText(buddy.getNick()); 82 | } 83 | if (!StringUtils.equals(signLbl.getText(), buddy.getSign())) { 84 | signLbl.setText(buddy.getSign()); 85 | } 86 | return view; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/renderer/node/CategoryNode.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.renderer.node; 2 | 3 | import com.alee.laf.label.WebLabel; 4 | import iqq.api.bean.IMCategory; 5 | 6 | import javax.swing.tree.DefaultMutableTreeNode; 7 | 8 | /** 9 | * 好友分类、聊天室分类显示节点 10 | *

11 | * Project : iqq-projects 12 | * Author : 承∮诺 < 6208317@qq.com > 13 | * Created : 14-5-10 14 | * License : Apache License 2.0 15 | */ 16 | public class CategoryNode extends DefaultMutableTreeNode { 17 | private IMCategory category; 18 | private WebLabel view = new WebLabel(); 19 | 20 | public CategoryNode(IMCategory category) { 21 | super(); 22 | this.category = category; 23 | 24 | view.setMargin(5, 8, 5, 5); 25 | } 26 | 27 | public IMCategory getCategory() { 28 | return category; 29 | } 30 | 31 | public void setCategory(IMCategory category) { 32 | this.category = category; 33 | } 34 | 35 | /** 36 | * 这个方法特别频繁,一定要处理好 37 | * 38 | * @return 39 | */ 40 | public WebLabel getView() { 41 | if (!view.getText().equals(category.getName())) { 42 | view.setText(category.getName()); 43 | } 44 | return view; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/renderer/node/EntityNode.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.renderer.node; 2 | 3 | import iqq.api.bean.IMEntity; 4 | 5 | import javax.swing.tree.DefaultMutableTreeNode; 6 | 7 | /** 8 | * Project : iqq-projects 9 | * Author : 承∮诺 < 6208317@qq.com > 10 | * Created : 14-5-11 11 | * License : Apache License 2.0 12 | */ 13 | public class EntityNode extends DefaultMutableTreeNode { 14 | public EntityNode(IMEntity entity) { 15 | super(entity); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/renderer/node/RoomNode.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.renderer.node; 2 | 3 | import com.alee.laf.label.WebLabel; 4 | import com.alee.utils.ImageUtils; 5 | import iqq.api.bean.IMRoom; 6 | 7 | import java.awt.image.BufferedImage; 8 | 9 | /** 10 | * 聊天室显示节点 11 | *

12 | * Project : iqq-projects 13 | * Author : 承∮诺 < 6208317@qq.com > 14 | * Created : 14-5-10 15 | * License : Apache License 2.0 16 | */ 17 | public class RoomNode extends EntityNode { 18 | private IMRoom room; 19 | private BufferedImage avatar; 20 | private WebLabel view = new WebLabel(); 21 | 22 | public RoomNode(IMRoom room) { 23 | super(room); 24 | this.room = room; 25 | 26 | view.setMargin(5); 27 | } 28 | 29 | public IMRoom getRoom() { 30 | return room; 31 | } 32 | 33 | public void setRoom(IMRoom room) { 34 | this.room = room; 35 | } 36 | 37 | public WebLabel getView() { 38 | return getView(30, 30); 39 | } 40 | 41 | /** 42 | * 这个方法特别频繁,一定要处理好 43 | * 44 | * @return 45 | */ 46 | public WebLabel getView(int iconWidth, int iconHeight) { 47 | if (!view.getText().equals(room.getNick())) { 48 | view.setText(room.getNick()); 49 | } 50 | if (avatar == null || !avatar.equals(room.getAvatar())) { 51 | avatar = room.getAvatarBuffered(); 52 | view.setIcon(ImageUtils.createPreviewIcon(avatar, 43)); 53 | } 54 | return view; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/ui/skin/Skin.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui.skin; 2 | 3 | import iqq.app.core.service.SkinService; 4 | 5 | /** 6 | * Project : iqq-projects 7 | * Author : 承∮诺 < 6208317@qq.com > 8 | * Created : 14-5-4 9 | * License : Apache License 2.0 10 | */ 11 | public interface Skin { 12 | public void installSkin(SkinService skinService); 13 | } 14 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/util/Benchmark.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * Project : WebQQCore 20 | * Package : iqq.im.util 21 | * File : Benchmark.java 22 | * Author : solosky < solosky772@qq.com > 23 | * Created : 2013-4-7 24 | * License : Apache License 2.0 25 | */ 26 | package iqq.app.util; 27 | 28 | import org.slf4j.LoggerFactory; 29 | 30 | import java.util.Date; 31 | import java.util.Deque; 32 | import java.util.LinkedList; 33 | 34 | /** 35 | * 36 | * 一个工具类,可以用来跟踪程序效率问题 37 | * 目前暂时不支持多线程 38 | * 39 | * @author solosky 40 | * 41 | */ 42 | public class Benchmark { 43 | private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(Benchmark.class); 44 | private static Deque benchStack = new LinkedList(); 45 | 46 | 47 | public static void start(String tag) { 48 | BenchEntry entry = new BenchEntry(); 49 | entry.tag = tag; 50 | entry.depth = benchStack.size(); 51 | entry.start = new Date(); 52 | benchStack.addFirst(entry); 53 | } 54 | 55 | public static void end(String tag) { 56 | BenchEntry entry = benchStack.pollFirst(); 57 | if (!entry.tag.equals(tag)) { 58 | LOG.warn("Benchmark Not Match, tag spell mistake or forgot Benchmark.end(tag) invoke at somewhere ??"); 59 | return; 60 | } 61 | 62 | entry.end = new Date(); 63 | long used = entry.end.getTime() - entry.start.getTime(); 64 | LOG.debug("Benchmark [" + entry.tag + " ] - Used: " + (used) + " ms. "); 65 | } 66 | 67 | private static class BenchEntry { 68 | public long depth; 69 | public String tag; 70 | public Date start; 71 | public Date end; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/util/date/BaseDate.java: -------------------------------------------------------------------------------- 1 | package iqq.app.util.date; 2 | 3 | /** 4 | * Created by Tony on 3/28/15. 5 | */ 6 | public class BaseDate extends java.util.Date { 7 | 8 | public BaseDate() { 9 | super(); 10 | } 11 | 12 | public BaseDate(long milliseconds) { 13 | super(milliseconds); 14 | } 15 | 16 | public BaseDate(java.util.Date date) { 17 | super(date.getTime()); 18 | } 19 | 20 | /** 21 | * yyyy-MM-dd 22 | * 23 | * @return 24 | */ 25 | public String toDate() { 26 | return Date.formatFor(this); 27 | } 28 | 29 | /** 30 | * yyyy-MM-dd HH:mm:ss 31 | * 32 | * @return 33 | */ 34 | public String toDateTime() { 35 | return DateTime.formatFor(this); 36 | } 37 | 38 | /** 39 | * yyyy年MM月dd日 40 | * 41 | * @return 42 | */ 43 | public String toDateCN() { 44 | return Date.FORMATTER_CN.format(this); 45 | } 46 | 47 | /** 48 | * yyyy年MM月dd日 HH:mm:ss 49 | * 50 | * @return 51 | */ 52 | public String toDateTimeCN() { 53 | return DateTime.FORMATTER_CN.format(this); 54 | } 55 | 56 | /** 57 | * {0}秒之前 58 | * {0}分钟之前 59 | * {0}小时之前 60 | * {0}天之前 61 | * MM月dd日 HH:mm 62 | * yyyy年MM月dd日 HH:mm 63 | * 64 | * @return 65 | */ 66 | public String toFriendly() { 67 | return new FriendlyDate(getTime()).toFriendlyDate(true); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/util/date/Date.java: -------------------------------------------------------------------------------- 1 | package iqq.app.util.date; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | 6 | /** 7 | * 日期时间类 8 | * yyyy-MM-dd 9 | *

10 | * Created by Tony on 1/5/15. 11 | */ 12 | public class Date extends BaseDate { 13 | public final static SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd"); 14 | public final static SimpleDateFormat FORMATTER_CN = new SimpleDateFormat("yyyy年MM月dd日"); 15 | 16 | /** 17 | * string to date 18 | * 19 | * @param string 20 | * @return 21 | */ 22 | public static Date parseFor(String string) { 23 | java.util.Date date = null; 24 | try { 25 | date = FORMATTER.parse(string); 26 | } catch (ParseException e) { 27 | e.printStackTrace(); 28 | } 29 | return new Date(date); 30 | } 31 | 32 | /** 33 | * date to string 34 | * 35 | * @param date 36 | * @return 37 | */ 38 | public static String formatFor(BaseDate date) { 39 | return FORMATTER.format(date); 40 | } 41 | 42 | /** 43 | * 新建一个日期类 44 | * 45 | * @return 46 | */ 47 | public static Date newInstance() { 48 | // now to yyyy-MM-dd 49 | String nowDate = FORMATTER.format(new java.util.Date()); 50 | try { 51 | return new Date(FORMATTER.parse(nowDate)); 52 | } catch (ParseException e) { 53 | e.printStackTrace(); 54 | } 55 | return new Date(System.currentTimeMillis()); 56 | } 57 | 58 | public Date(long readLong) { 59 | super(readLong); 60 | } 61 | 62 | public Date(java.util.Date date) { 63 | super(date.getTime()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/util/date/DateTime.java: -------------------------------------------------------------------------------- 1 | package iqq.app.util.date; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | 6 | /** 7 | * 日期时间类 8 | * yyyy-MM-dd HH:mm:ss 9 | *

10 | * Created by Tony on 1/5/15. 11 | */ 12 | public class DateTime extends BaseDate { 13 | public final static SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 14 | public final static SimpleDateFormat FORMATTER_CN = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); 15 | 16 | /** 17 | * string to date 18 | * 19 | * @param string 20 | * @return 21 | */ 22 | public static DateTime parseFor(String string) { 23 | java.util.Date date = null; 24 | try { 25 | date = FORMATTER.parse(string); 26 | } catch (ParseException e) { 27 | e.printStackTrace(); 28 | } 29 | return new DateTime(date); 30 | } 31 | 32 | /** 33 | * date to string 34 | * 35 | * @param date 36 | * @return 37 | */ 38 | public static String formatFor(BaseDate date) { 39 | return FORMATTER.format(date); 40 | } 41 | 42 | /** 43 | * 新建一个日期时间类 44 | * 45 | * @return 46 | */ 47 | public static DateTime newInstance() { 48 | // now to yyyy-MM-dd 49 | String nowDate = FORMATTER.format(new java.util.Date()); 50 | try { 51 | return new DateTime(FORMATTER.parse(nowDate)); 52 | } catch (ParseException e) { 53 | e.printStackTrace(); 54 | } 55 | return new DateTime(System.currentTimeMillis()); 56 | } 57 | 58 | public DateTime(long readLong) { 59 | super(readLong); 60 | } 61 | 62 | public DateTime(java.util.Date date) { 63 | super(date.getTime()); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/util/date/DateTimeZone.java: -------------------------------------------------------------------------------- 1 | package iqq.app.util.date; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | 6 | /** 7 | * 日期时间类 8 | * yyyy-MM-dd'T'HH:mm:ssZ 9 | *

10 | * Created by Tony on 1/5/15. 11 | */ 12 | public class DateTimeZone extends BaseDate { 13 | public final static SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); 14 | public final static SimpleDateFormat FORMATTER_CN = new SimpleDateFormat("yyyy年MM月dd日'T'HH:mm:ssZ"); 15 | 16 | /** 17 | * string to date 18 | * 19 | * @param string 20 | * @return 21 | */ 22 | public static DateTimeZone parseFor(String string) { 23 | java.util.Date date = null; 24 | try { 25 | date = FORMATTER.parse(string); 26 | } catch (ParseException e) { 27 | e.printStackTrace(); 28 | } 29 | return new DateTimeZone(date); 30 | } 31 | 32 | /** 33 | * date to string 34 | * 35 | * @param date 36 | * @return 37 | */ 38 | public static String formatFor(BaseDate date) { 39 | return FORMATTER.format(date); 40 | } 41 | 42 | /** 43 | * 新建一个日期时间类 44 | * 45 | * @return 46 | */ 47 | public static DateTime newInstance() { 48 | // now to yyyy-MM-dd 49 | String nowDate = FORMATTER.format(new java.util.Date()); 50 | try { 51 | return new DateTime(FORMATTER.parse(nowDate)); 52 | } catch (ParseException e) { 53 | e.printStackTrace(); 54 | } 55 | return new DateTime(System.currentTimeMillis()); 56 | } 57 | 58 | public DateTimeZone(long readLong) { 59 | super(readLong); 60 | } 61 | 62 | public DateTimeZone(java.util.Date date) { 63 | super(date.getTime()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/util/gson/DateFormatter.java: -------------------------------------------------------------------------------- 1 | package iqq.app.util.gson; 2 | 3 | import com.google.gson.*; 4 | import iqq.app.util.date.Date; 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | import java.lang.reflect.Type; 8 | 9 | /** 10 | * 日期格式化 yyyy-MM-dd 11 | *

12 | * Created by Tony on 1/5/15. 13 | */ 14 | public class DateFormatter implements JsonDeserializer, JsonSerializer { 15 | private static final String TAG = DateFormatter.class.getName(); 16 | 17 | /** 18 | * string to date 19 | * 20 | * @param json 21 | * @param typeOfT 22 | * @param context 23 | * @return 24 | * @throws JsonParseException 25 | */ 26 | public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 27 | throws JsonParseException { 28 | 29 | String value = json.getAsString(); 30 | if (StringUtils.isEmpty(value) || value.length() == 1) { 31 | return null; 32 | } 33 | 34 | return Date.parseFor(value); 35 | } 36 | 37 | /** 38 | * date to string 39 | * 40 | * @param date 41 | * @param type 42 | * @param context 43 | * @return 44 | */ 45 | public JsonElement serialize(Date date, Type type, JsonSerializationContext context) { 46 | return new JsonPrimitive(Date.formatFor(date)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/util/gson/DateTimeFormatter.java: -------------------------------------------------------------------------------- 1 | package iqq.app.util.gson; 2 | 3 | import com.google.gson.JsonDeserializationContext; 4 | import com.google.gson.JsonDeserializer; 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.JsonParseException; 7 | import com.google.gson.JsonPrimitive; 8 | import com.google.gson.JsonSerializationContext; 9 | import com.google.gson.JsonSerializer; 10 | import iqq.app.util.date.DateTime; 11 | import org.apache.commons.lang3.StringUtils; 12 | 13 | import java.lang.reflect.Type; 14 | 15 | 16 | /** 17 | * 日期格式化 yyyy-MM-dd 18 | *

19 | * Created by Tony on 1/5/15. 20 | */ 21 | public class DateTimeFormatter implements JsonDeserializer, JsonSerializer { 22 | private static final String TAG = DateTimeFormatter.class.getName(); 23 | 24 | /** 25 | * string to date 26 | * 27 | * @param json 28 | * @param typeOfT 29 | * @param context 30 | * @return 31 | * @throws JsonParseException 32 | */ 33 | public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 34 | throws JsonParseException { 35 | 36 | String value = json.getAsString(); 37 | if (StringUtils.isEmpty(value) || value.length() == 1) { 38 | return null; 39 | } 40 | 41 | return DateTime.parseFor(value); 42 | } 43 | 44 | /** 45 | * date to string 46 | * 47 | * @param date 48 | * @param type 49 | * @param context 50 | * @return 51 | */ 52 | public JsonElement serialize(DateTime date, Type type, JsonSerializationContext context) { 53 | return new JsonPrimitive(DateTime.formatFor(date)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /main/src/main/java/iqq/app/util/gson/DateTimeZoneFormatter.java: -------------------------------------------------------------------------------- 1 | package iqq.app.util.gson; 2 | 3 | import com.google.gson.*; 4 | import iqq.app.util.date.DateTimeZone; 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | import java.lang.reflect.Type; 8 | 9 | 10 | /** 11 | * 日期格式化 yyyy-MM-dd 12 | *

13 | * Created by Tony on 1/5/15. 14 | */ 15 | public class DateTimeZoneFormatter implements JsonDeserializer, JsonSerializer { 16 | private static final String TAG = DateTimeZoneFormatter.class.getName(); 17 | 18 | /** 19 | * string to date 20 | * 21 | * @param json 22 | * @param typeOfT 23 | * @param context 24 | * @return 25 | * @throws JsonParseException 26 | */ 27 | public DateTimeZone deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 28 | throws JsonParseException { 29 | 30 | String value = json.getAsString(); 31 | if (StringUtils.isEmpty(value) || value.length() == 1) { 32 | return null; 33 | } 34 | 35 | return DateTimeZone.parseFor(value); 36 | } 37 | 38 | /** 39 | * date to string 40 | * 41 | * @param date 42 | * @param type 43 | * @param context 44 | * @return 45 | */ 46 | public JsonElement serialize(DateTimeZone date, Type type, JsonSerializationContext context) { 47 | return new JsonPrimitive(DateTimeZone.formatFor(date)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /main/src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: iqq.app.IMLauncher 3 | 4 | -------------------------------------------------------------------------------- /main/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | [%d{yyyy/MM/dd HH:mm:ss.SSS}][%p][%logger:%L] %m%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /main/src/main/resources/spring-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /main/src/test/java/iqq/app/TestIoc.java: -------------------------------------------------------------------------------- 1 | package iqq.app; 2 | 3 | import iqq.app.core.context.IMContext; 4 | import iqq.app.core.service.SkinService; 5 | import iqq.app.core.service.impl.SkinServiceImpl; 6 | import junit.framework.Assert; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | /** 11 | * Project : iqq 12 | * Author : 承∮诺 < 6208317@qq.com > 13 | * Created : 14-4-16 14 | * License : Apache License 2.0 15 | */ 16 | public class TestIoc { 17 | @Before 18 | public void before() { 19 | 20 | } 21 | 22 | @Test 23 | public void testBean() { 24 | SkinService skinService = IMContext.getBean(SkinServiceImpl.class); 25 | Assert.assertNotNull(skinService); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /main/src/test/java/iqq/app/TestPath.java: -------------------------------------------------------------------------------- 1 | package iqq.app; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * Project : iqq 7 | * Author : 承∮诺 < 6208317@qq.com > 8 | * Created : 14-4-16 9 | * License : Apache License 2.0 10 | */ 11 | public class TestPath { 12 | @Test 13 | public void testProjectDir() { 14 | System.out.println(System.getProperty("user.dir")); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /main/src/test/java/iqq/app/service/TestI18nService.java: -------------------------------------------------------------------------------- 1 | package iqq.app.service; 2 | 3 | import iqq.app.core.context.IMContext; 4 | import iqq.app.core.service.I18nService; 5 | import iqq.app.core.service.impl.I18nServiceImpl; 6 | import org.junit.Assert; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | /** 11 | * Created by Administrator on 2014/4/17. 12 | */ 13 | public class TestI18nService { 14 | I18nService i18nService; 15 | 16 | @Before 17 | public void before() { 18 | i18nService = IMContext.getBean(I18nServiceImpl.class); 19 | } 20 | 21 | @Test 22 | public void testDefault() { 23 | //Locale.setDefault(Locale.CANADA); 24 | Assert.assertNotNull(i18nService); 25 | Assert.assertNotNull(i18nService.getMessage("login")); 26 | System.out.println(i18nService.getMessage("conversationTitle", " TEST")); 27 | System.out.println(i18nService.getMessage("login")); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /main/src/test/java/iqq/app/service/TestResourceService.java: -------------------------------------------------------------------------------- 1 | package iqq.app.service; 2 | 3 | import iqq.app.core.context.IMContext; 4 | import iqq.app.core.service.ResourceService; 5 | import iqq.app.core.service.impl.ResourceServiceImpl; 6 | import junit.framework.Assert; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.io.File; 11 | 12 | /** 13 | * Project : iqq 14 | * Author : 承∮诺 < 6208317@qq.com > 15 | * Created : 14-4-17 16 | * License : Apache License 2.0 17 | */ 18 | public class TestResourceService { 19 | 20 | ResourceService resourceService = null; 21 | 22 | @Before 23 | public void before() { 24 | resourceService = IMContext.getBean(ResourceServiceImpl.class); 25 | } 26 | 27 | @Test 28 | public void testResourcesPath() { 29 | String path = resourceService.getResourcePath() + "login/avatar.jpg"; 30 | System.out.println(path); 31 | Assert.assertNotNull(path); 32 | Assert.assertTrue(new File(path).exists()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /main/src/test/java/iqq/app/service/TestSkinService.java: -------------------------------------------------------------------------------- 1 | package iqq.app.service; 2 | 3 | import com.alee.extended.painter.Painter; 4 | import iqq.app.core.service.SkinService; 5 | import iqq.app.core.service.impl.SkinServiceImpl; 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | 9 | import javax.swing.*; 10 | import java.io.File; 11 | 12 | /** 13 | * Project : iqq 14 | * Author : 承∮诺 < 6208317@qq.com > 15 | * Created : 14-4-16 16 | * License : Apache License 2.0 17 | */ 18 | public class TestSkinService { 19 | @Test 20 | public void testPath() { 21 | //System.setProperty("app.dir", ""); 22 | SkinService skinService = new SkinServiceImpl(); 23 | String path = skinService.getDirectory(); 24 | System.out.println(path); 25 | Assert.assertNotNull(path); 26 | Assert.assertTrue(new File(path).exists()); 27 | } 28 | 29 | @Test 30 | public void testCustomPath() { 31 | SkinService skinService = new SkinServiceImpl(); 32 | String path = skinService.getDirectory(); 33 | System.out.println(path); 34 | skinService.setDirectory("skins/test"); 35 | skinService.setEnableCustom(false); 36 | } 37 | 38 | @Test 39 | public void testColor() { 40 | SkinService skinService = new SkinServiceImpl(); 41 | 42 | System.out.println(skinService.getColorByKey("window/titleColor1")); 43 | } 44 | 45 | @Test 46 | public void tesIcon() { 47 | SkinService skinService = new SkinServiceImpl(); 48 | Assert.assertTrue(skinService.getIconByKey("window/titleIcon") instanceof ImageIcon); 49 | Assert.assertTrue(skinService.getPainterByKey("login/background") instanceof Painter); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /main/src/test/java/iqq/app/ui/TestLogin.java: -------------------------------------------------------------------------------- 1 | package iqq.app.ui; 2 | 3 | import com.alee.laf.WebLookAndFeel; 4 | import iqq.app.ui.frame.LoginFrame; 5 | import iqq.app.ui.frame.VerifyFrame; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import java.util.Scanner; 10 | 11 | /** 12 | * Project : iqq 13 | * Author : 承∮诺 < 6208317@qq.com > 14 | * Created : 14-4-16 15 | * License : Apache License 2.0 16 | */ 17 | public class TestLogin { 18 | 19 | @Before 20 | public void before() { 21 | WebLookAndFeel.install(); 22 | } 23 | 24 | @Test 25 | public void testLoginBg() { 26 | LoginFrame login = new LoginFrame(); 27 | new Scanner(System.in).next(); 28 | } 29 | 30 | @Test 31 | public void testVerification() { 32 | VerifyFrame ver = new VerifyFrame(); 33 | ver.setVisible(true); 34 | new Scanner(System.in).next(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /main/src/test/java/iqq/app/util/TestXml.java: -------------------------------------------------------------------------------- 1 | package iqq.app.util; 2 | 3 | import org.dom4j.Document; 4 | import org.dom4j.DocumentException; 5 | import org.dom4j.DocumentHelper; 6 | import org.dom4j.Element; 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | 12 | /** 13 | * Project : iqq 14 | * Author : 承∮诺 < 6208317@qq.com > 15 | * Created : 14-4-16 16 | * License : Apache License 2.0 17 | */ 18 | public class TestXml { 19 | 20 | @Test 21 | public void testWrite() { 22 | String xmlFile = System.getProperty("user.dir") + "/config.xml"; 23 | Document doc = DocumentHelper.createDocument(); 24 | 25 | Element root = doc.addElement("roots"); 26 | root.addElement("test").setText("test123"); 27 | 28 | Element element = root.addElement("iqq"); 29 | element.addElement("version").setText("iqqv3"); 30 | 31 | // 测试XmlUtils 32 | try { 33 | XmlUtils.writeXml(xmlFile, doc); 34 | } catch (IOException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | 39 | @Test 40 | public void testRead() { 41 | String xmlFile = System.getProperty("user.dir") + "/config.xml"; 42 | try { 43 | String text = XmlUtils.getNodeText(xmlFile, "iqq/version"); 44 | System.out.println(text); 45 | Assert.assertNotNull(text); 46 | } catch (DocumentException e) { 47 | e.printStackTrace(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /resources/i18n/appBundle.properties: -------------------------------------------------------------------------------- 1 | #login 2 | login.account = Account 3 | login.password = Password 4 | login.login = Login 5 | login.forgetPwd=Forget Password 6 | login.rememberPwd=Remember Password 7 | login.regAccount=Register 8 | login.cancel = Cancel 9 | login.inputUsername = Please enter a username! 10 | login.inputPassword = Please enter your password! 11 | login.netError = Unable to connect to Q+ Server, please check your connection and try again! 12 | login.failed = Login Failed! 13 | 14 | veriry.verify=Verify 15 | veriry.reset=Verify Reset 16 | verify.freshVerifyFailed = Fresh verify image failed! Retry it ? 17 | 18 | #main panel 19 | contacts = Contacts 20 | groups = Groups 21 | recently =Recent 22 | setting=Setting 23 | confirm=OK 24 | cancel = Cancel 25 | app.name=IQQ 26 | app.skinSetting=Skin Settings 27 | 28 | status.online=Online 29 | status.callme=Callme 30 | status.away=Away 31 | status.meeting=Meeting 32 | status.silent=Silent 33 | status.hidden=Hidden 34 | status.offline=Offline 35 | findContact=Find a contact... 36 | minimize=Minimize 37 | maximize=Maximize 38 | close=Close 39 | myDiscuz=My Discuz 40 | myGroup=My Group 41 | conversationTitle= Conversation With {0} 42 | sendMsgEmpty=The message cannot be empty. Please enter again. 43 | chat.text=Font 44 | chat.emoticon=Emoticon 45 | chat.screenCapture=ScreenCapture 46 | chat.shake=Shake 47 | chat.pictures=Pictures 48 | chat.history=History 49 | chat.send=Send Message 50 | chat.picNotSupported = Current version is not supported send group or discuz picture for Q+ protocol limit. 51 | chat.recvShake = contact has sent a shake message. 52 | chat.sendShake = you have sent a shake message. 53 | chat.msg.read = Read 54 | chat.picLengthNotSupported=The pictures filesize exceeds the limit of 1MB. 55 | chat.msg.unread = Unread 56 | chat.msg.pending = Pending.. 57 | chat.msg.error = Send Failed.. 58 | chat.msg.sent = Sent 59 | chat.userInputting = Writing.. 60 | userView=User View 61 | groupView=Group View 62 | conversationView=Conversation View 63 | bigFace=Big Face 64 | smallFace=Small Face 65 | chat.setting=Setting 66 | customFace=Custom Face 67 | normalFace=Normal Face 68 | chat.fileTransfer=File Transfer 69 | chat.showMembers=Show Members 70 | netOffline=You are offline because of a connection problem. 71 | chat.selfOffline=You are offline now. 72 | 73 | user.gender=Gender 74 | user.age=Age 75 | user.country=Country 76 | user.province=Province 77 | user.occupation=Occupation 78 | user.level=Level 79 | user.clientType=Client Type 80 | user.email=Email 81 | user.male=Male 82 | user.female=Female 83 | -------------------------------------------------------------------------------- /resources/i18n/appBundle_zh_CN.properties: -------------------------------------------------------------------------------- 1 | #login 2 | login.account = \u8D26\u53F7 3 | login.password = \u5BC6\u7801 4 | login.rememberPwd=\u8BB0\u4F4F\u5BC6\u7801 5 | login.regAccount=\u6CE8\u518C\u8D26\u53F7 6 | login.forgetPwd=\u5FD8\u8BB0\u5BC6\u7801 7 | login.login = \u767B\u5F55 8 | login.cancel = \u53D6\u6D88 9 | login.inputUsername = \u8BF7\u8F93\u5165\u8D26\u53F7\u3002 10 | login.inputPassword = \u8BF7\u8F93\u5165\u5BC6\u7801\u3002 11 | login.netError = \u65E0\u6CD5\u8FDE\u63A5Q+\u670D\u52A1\u5668\uFF0C\u8BF7\u68C0\u67E5\u60A8\u7684\u7F51\u7EDC\u8FDE\u63A5\u7136\u540E\u91CD\u8BD5\u3002 12 | login.failed = \u767B\u5F55\u5931\u8D25\uFF01 13 | 14 | veriry.verify=\u9A8C\u8BC1\u7801 15 | veriry.reset=\u770B\u4E0D\u6E05\u695A\uFF0C\u6362\u4E00\u5F20\u3002 16 | verify.freshVerifyFailed = \u5237\u65B0\u9A8C\u8BC1\u7801\u5931\u8D25\uFF0C\u662F\u5426\u91CD\u8BD5\uFF1F 17 | 18 | sendMsgEmpty=\u53D1\u9001\u7684\u6D88\u606F\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165\u3002 19 | userView=\u7528\u6237\u663E\u793A 20 | groupView=\u7FA4\u7EC4\u663E\u793A 21 | conversationView=\u4F1A\u8BDD\u663E\u793A 22 | setting=\u8BBE\u7F6E 23 | bigFace=\u5927\u5934\u50CF 24 | smallFace=\u5C0F\u5934\u50CF 25 | customFace=\u81EA\u5B9A\u4E49\u5934\u50CF 26 | normalFace=\u4E2D\u5934\u50CF 27 | 28 | #main panel 29 | contacts = \u8054\u7CFB\u4EBA 30 | groups = \u7FA4\u4E0E\u8BA8\u8BBA\u7EC4 31 | recently =\u6700\u8FD1\u8054\u7CFB 32 | app.name=IQQ 33 | minimize=\u6700\u5C0F\u5316 34 | maximize=\u6700\u5927\u5316 35 | close=\u5173\u95ED 36 | confirm=\u786E\u5B9A 37 | cancel = \u53D6\u6D88 38 | myGroup=\u6211\u7684QQ\u7FA4 39 | myDiscuz=\u6211\u7684\u8BA8\u8BBA\u7EC4 40 | status.online=\u5728\u7EBF 41 | status.callme=Q\u6211\u5427 42 | status.away=\u79BB\u5F00 43 | status.meeting=\u5FD9\u788C 44 | status.silent=\u8BF7\u52FF\u6253\u6270 45 | status.hidden=\u9690\u8EAB 46 | status.offline=\u79BB\u7EBF 47 | findContact=\u641C\u7D22\uFF1A\u8054\u7CFB\u4EBA... 48 | conversationTitle=\u4E0E {0} \u7684\u5BF9\u8BDD 49 | chat.text=\u5B57\u4F53 50 | chat.emoticon=\u8868\u60C5 51 | chat.screenCapture=\u622A\u56FE 52 | chat.shake=\u9707\u52A8 53 | chat.pictures=\u56FE\u7247 54 | chat.history=\u5386\u53F2\u8BB0\u5F55 55 | chat.send=\u53D1\u9001\u6D88\u606F 56 | chat.msg.read = \u5DF2\u8BFB 57 | chat.msg.unread = \u672A\u8BFB 58 | chat.setting=\u8BBE\u7F6E 59 | chat.msg.pending = \u7B49\u5F85\u53D1\u9001.. 60 | chat.msg.error = \u53D1\u9001\u5931\u8D25.. 61 | chat.msg.sent = \u5DF2\u53D1\u9001 62 | chat.picNotSupported=\u62B1\u6B49\uFF0C\u7531\u4E8EQ+\u534F\u8BAE\u9650\u5236\uFF0C\u5F53\u524D\u7248\u672C\u4E0D\u652F\u6301\u53D1\u9001\u7FA4\u6216\u8BA8\u8BBA\u7EC4\u56FE\u7247\u3002 63 | chat.picLengthNotSupported=\u62B1\u6B49\uFF0C\u7531\u4E8EQ+\u534F\u8BAE\u9650\u5236\uFF0C\u53D1\u9001\u56FE\u7247\u4E0D\u80FD\u8D85\u8FC71MB\u5927\u5C0F\u3002 64 | chat.recvShake = \u5BF9\u65B9\u7ED9\u60A8\u53D1\u9001\u4E86\u4E00\u4E2A\u7A97\u53E3\u6296\u52A8\u3002 65 | chat.sendShake =\u60A8\u7ED9\u5BF9\u65B9\u53D1\u9001\u4E86\u4E00\u4E2A\u7A97\u53E3\u6296\u52A8\u3002 66 | chat.fileTransfer=\u6587\u4EF6\u4F20\u8F93 67 | chat.showMembers=\u663E\u793A\u6210\u5458 68 | chat.userInputting=\u6B63\u5728\u8F93\u5165.. 69 | netOffline = \u7531\u4E8E\u7F51\u7EDC\u539F\u56E0\uFF0C\u60A8\u5DF2\u7ECF\u79BB\u7EBF\u3002 70 | chat.selfOffline = \u60A8\u5DF2\u7ECF\u79BB\u7EBF\u3002 71 | 72 | user.gender=\u6027\u522B 73 | user.age=\u5E74\u9F84 74 | user.country=\u56FD\u5BB6 75 | user.province=\u7701 76 | user.occupation=\u804C\u4E1A 77 | user.email=\u90AE\u7BB1 78 | user.level=\u7B49\u7EA7 79 | user.clientType=\u5BA2\u6237\u7AEF\u7C7B\u578B 80 | user.male=\u7537 81 | user.female=\u5973 82 | app.skinSetting=\u76AE\u80A4\u8BBE\u7F6E 83 | -------------------------------------------------------------------------------- /resources/icons/default/qq_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/default/qq_icon.png -------------------------------------------------------------------------------- /resources/icons/login/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/login/avatar.jpg -------------------------------------------------------------------------------- /resources/icons/login/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/login/avatar.png -------------------------------------------------------------------------------- /resources/icons/login/avatar2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/login/avatar2.png -------------------------------------------------------------------------------- /resources/icons/login/captcha.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/login/captcha.jpg -------------------------------------------------------------------------------- /resources/icons/login/face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/login/face.jpg -------------------------------------------------------------------------------- /resources/icons/login/group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/login/group.png -------------------------------------------------------------------------------- /resources/icons/login/qq_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/login/qq_icon.png -------------------------------------------------------------------------------- /resources/icons/status/away.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/status/away.png -------------------------------------------------------------------------------- /resources/icons/status/callme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/status/callme.png -------------------------------------------------------------------------------- /resources/icons/status/hidden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/status/hidden.png -------------------------------------------------------------------------------- /resources/icons/status/meeting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/status/meeting.png -------------------------------------------------------------------------------- /resources/icons/status/offline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/status/offline.png -------------------------------------------------------------------------------- /resources/icons/status/online.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/status/online.png -------------------------------------------------------------------------------- /resources/icons/status/silent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/icons/status/silent.png -------------------------------------------------------------------------------- /resources/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | iqq.app 9 | iqq 10 | 3.0.0-SNAPSHOT 11 | 12 | 13 | iqq-resources 14 | jar 15 | iqq资源文件模块 16 | 17 | 18 | -------------------------------------------------------------------------------- /resources/screenshots/chat-msg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/screenshots/chat-msg.png -------------------------------------------------------------------------------- /resources/screenshots/chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/screenshots/chat.png -------------------------------------------------------------------------------- /resources/screenshots/main-skin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/screenshots/main-skin.png -------------------------------------------------------------------------------- /resources/screenshots/main-skin2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/screenshots/main-skin2.png -------------------------------------------------------------------------------- /resources/screenshots/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/resources/screenshots/main.png -------------------------------------------------------------------------------- /skin-default/chat/bg/balloon/balloon_left_blue.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/bg/balloon/balloon_left_blue.9.png -------------------------------------------------------------------------------- /skin-default/chat/bg/balloon/balloon_left_green.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/bg/balloon/balloon_left_green.9.png -------------------------------------------------------------------------------- /skin-default/chat/bg/balloon/balloon_left_white.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/bg/balloon/balloon_left_white.9.png -------------------------------------------------------------------------------- /skin-default/chat/bg/balloon/balloon_right_blue.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/bg/balloon/balloon_right_blue.9.png -------------------------------------------------------------------------------- /skin-default/chat/bg/balloon/balloon_right_grey.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/bg/balloon/balloon_right_grey.9.png -------------------------------------------------------------------------------- /skin-default/chat/bg/nav_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/bg/nav_bg.9.png -------------------------------------------------------------------------------- /skin-default/chat/icons/inputbar/emoticon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/icons/inputbar/emoticon.png -------------------------------------------------------------------------------- /skin-default/chat/icons/inputbar/fileTransfere.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/icons/inputbar/fileTransfere.png -------------------------------------------------------------------------------- /skin-default/chat/icons/inputbar/history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/icons/inputbar/history.png -------------------------------------------------------------------------------- /skin-default/chat/icons/inputbar/noMessage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/icons/inputbar/noMessage.png -------------------------------------------------------------------------------- /skin-default/chat/icons/inputbar/offMessage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/icons/inputbar/offMessage.png -------------------------------------------------------------------------------- /skin-default/chat/icons/inputbar/pictures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/icons/inputbar/pictures.png -------------------------------------------------------------------------------- /skin-default/chat/icons/inputbar/screenCapture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/icons/inputbar/screenCapture.png -------------------------------------------------------------------------------- /skin-default/chat/icons/inputbar/send.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/icons/inputbar/send.png -------------------------------------------------------------------------------- /skin-default/chat/icons/inputbar/shake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/icons/inputbar/shake.png -------------------------------------------------------------------------------- /skin-default/chat/icons/inputbar/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/icons/inputbar/text.png -------------------------------------------------------------------------------- /skin-default/chat/icons/setting_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/chat/icons/setting_icon.png -------------------------------------------------------------------------------- /skin-default/font/wqy-microhei.ttc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/font/wqy-microhei.ttc -------------------------------------------------------------------------------- /skin-default/login/bg/footer_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/login/bg/footer_bg.9.png -------------------------------------------------------------------------------- /skin-default/login/bg/login_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/login/bg/login_bg.9.png -------------------------------------------------------------------------------- /skin-default/login/bg/login_bg2.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/login/bg/login_bg2.9.png -------------------------------------------------------------------------------- /skin-default/login/icons/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/login/icons/key.png -------------------------------------------------------------------------------- /skin-default/login/icons/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/login/icons/setting.png -------------------------------------------------------------------------------- /skin-default/login/icons/setting_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/login/icons/setting_active.png -------------------------------------------------------------------------------- /skin-default/main/bg/search_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/bg/search_bg.9.png -------------------------------------------------------------------------------- /skin-default/main/bg/tab_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/bg/tab_bg.9.png -------------------------------------------------------------------------------- /skin-default/main/icons/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/arrow_down.png -------------------------------------------------------------------------------- /skin-default/main/icons/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/arrow_left.png -------------------------------------------------------------------------------- /skin-default/main/icons/search_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/search_icon.png -------------------------------------------------------------------------------- /skin-default/main/icons/tab_boddy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/tab_boddy.png -------------------------------------------------------------------------------- /skin-default/main/icons/tab_group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/tab_group.png -------------------------------------------------------------------------------- /skin-default/main/icons/tab_recent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/tab_recent.png -------------------------------------------------------------------------------- /skin-default/main/icons/toolbar/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/toolbar/add.png -------------------------------------------------------------------------------- /skin-default/main/icons/toolbar/mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/toolbar/mail.png -------------------------------------------------------------------------------- /skin-default/main/icons/toolbar/msg_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/toolbar/msg_new.png -------------------------------------------------------------------------------- /skin-default/main/icons/toolbar/msg_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/toolbar/msg_normal.png -------------------------------------------------------------------------------- /skin-default/main/icons/toolbar/msgrecode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/toolbar/msgrecode.png -------------------------------------------------------------------------------- /skin-default/main/icons/toolbar/qzone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/toolbar/qzone.png -------------------------------------------------------------------------------- /skin-default/main/icons/toolbar/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/toolbar/setting.png -------------------------------------------------------------------------------- /skin-default/main/icons/toolbar/weibo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/main/icons/toolbar/weibo.png -------------------------------------------------------------------------------- /skin-default/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | iqq.app 9 | iqq 10 | 3.0.0-SNAPSHOT 11 | 12 | 13 | iqq-skins 14 | jar 15 | iqq默认皮肤资源模块 16 | 17 | -------------------------------------------------------------------------------- /skin-default/skin/bg/0.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/0.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/1.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/1.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/10.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/10.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/11.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/11.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/12.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/12.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/13.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/13.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/14.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/14.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/2.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/2.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/3.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/3.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/4.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/4.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/5.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/5.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/6.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/6.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/7.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/7.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/8.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/8.9.png -------------------------------------------------------------------------------- /skin-default/skin/bg/9.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/bg/9.9.png -------------------------------------------------------------------------------- /skin-default/skin/icons/skin_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/skin/icons/skin_icon.png -------------------------------------------------------------------------------- /skin-default/window/bg/transparent.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/bg/transparent.9.png -------------------------------------------------------------------------------- /skin-default/window/bg/window_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/bg/window_bg.9.png -------------------------------------------------------------------------------- /skin-default/window/icons/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/close.png -------------------------------------------------------------------------------- /skin-default/window/icons/close_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/close_active.png -------------------------------------------------------------------------------- /skin-default/window/icons/maximize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/maximize.png -------------------------------------------------------------------------------- /skin-default/window/icons/maximize_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/maximize_active.png -------------------------------------------------------------------------------- /skin-default/window/icons/minimize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/minimize.png -------------------------------------------------------------------------------- /skin-default/window/icons/minimize_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/minimize_active.png -------------------------------------------------------------------------------- /skin-default/window/icons/restore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/restore.png -------------------------------------------------------------------------------- /skin-default/window/icons/restore_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/restore_active.png -------------------------------------------------------------------------------- /skin-default/window/icons/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/setting.png -------------------------------------------------------------------------------- /skin-default/window/icons/setting_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/setting_active.png -------------------------------------------------------------------------------- /skin-default/window/icons/skin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/skin.png -------------------------------------------------------------------------------- /skin-default/window/icons/skin_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/skin_active.png -------------------------------------------------------------------------------- /skin-default/window/icons/title_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/title_icon.png -------------------------------------------------------------------------------- /skin-default/window/icons/title_w_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/title_w_icon.png -------------------------------------------------------------------------------- /skin-default/window/icons/title_w_icon_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tonybase/italk/78a6f41809d1eabf4235c7e7c66f447d931d7d71/skin-default/window/icons/title_w_icon_black.png --------------------------------------------------------------------------------