京山游俠
專注技術,拒絕扯淡
posts - 50, comments - 868, trackbacks - 0, articles - 0
BlogJava
::
首頁
::
新隨筆
::
聯(lián)系
::
聚合
::
管理
Eclipse RCP詳解(05):JFace和結構化數據
Posted on 2014-03-04 20:56
京山游俠
閱讀(5264)
評論(6)
編輯
收藏
所屬分類:
擁抱Eclipse RCP
上一篇
Eclipse RCP詳解(04):Eclipse RCP相關的學習資料及國內相關圖書點評
前面幾篇都是使用Ubuntu系統(tǒng)及其自帶的Eclipse 3.8.1。在這一篇里,我將為大家展示Fedora 20和其自帶的Eclipse 4.3.1。同時,為了方便我隨時切換操作系統(tǒng)(Ubuntu、Fedora、Win7),我在GitHub上注冊了一個賬號,并把示例代碼放了上去。我切換系統(tǒng)后,只需要Fetch一下,就可以繼續(xù)開發(fā)。當然,有興趣看我代碼的朋友,也可以clone一份到自己的機器上。地址:
https://github.com/littleloach/examples.git
關于Eclipse和Git的整合,請看這里:
淺論Maven和Git的原理及展示其與Eclipse的集成
事實證明,Eclipse RCP不僅是跨平臺的,而且是跨版本的。也就是說,即使我在Fedora中使用了不一樣的Eclipse版本,我在Ubuntu中寫的代碼到Fedora中也不需要修改。(我在Win7中用的Eclipse版本和Ubuntu中的相同。)
Fedora 20和Fedora 19都是我喜歡的版本。因為它們的開發(fā)代號分別為Heisenberg和薛定諤的貓,不難看出,它們都和量子力學有關,對我這樣的理工男吸引力那肯定是巨大的。而Heisenberg更具有傳奇性。不僅因為他是量子力學的主要創(chuàng)始人和諾貝爾獎獲得者,更因為歷史上到現(xiàn)在都沒有定論的海森堡謎題:為什么當初他沒有造出原子彈,是他真的搞錯了,還是他故意搞錯了?故事是這樣的:第二次世界大戰(zhàn)開始后,迫于納粹德國的威脅,丹麥的大物理學家玻爾離開了心愛的哥本哈根理論物理研究所,離開了朝夕相處的來自世界各地的同事,遠赴美國。德國的許多科學家也紛紛背井離鄉(xiāng),堅決不與納粹勢力妥協(xié)。然而,有一位同樣優(yōu)秀的物理學家卻留下來了,并被納粹德國委以重任,負責領導研制原子彈的技術工作,遠在異鄉(xiāng)的玻爾憤怒了,他與這位過去的同事產生了尖銳的矛盾,并與他形成了終生未能化解的隔閡。有趣的是,這位一直未能被玻爾諒解的科學家卻在1970年獲得了“玻爾國際獎章”,而這一獎章是用以表彰“在原子能和平利用方面做出了巨大貢獻的科學家或工程師”的。歷史在此開了個巨大的玩笑,這玩笑的主人公就像他發(fā)現(xiàn)的“測不準原理”一樣,一直讓人感到困惑和不解。他就是量子力學的創(chuàng)始人——海森堡。也許他當初就是故意留下來而且故意造不出原子彈的吧。
在正式介紹JFace和結構化數據之前,先向大家展示幾張Fedora的截圖。
第一張,F(xiàn)edora剛安裝完成后,其Gnome桌面是很丑的:
所以需要進行一些Art Work,比如多安裝幾個wallpaper啦,多安裝幾個theme啦,然后安裝一個gnome-tweak-tool更改一下字體、字體微調和抗鋸齒啦。Fedora 19和20還有一個地方比較令人蛋疼,那就是它提供的gnome-terminal是不支持半透明背景的,如果想要半透明背景,只有自己編譯gnome-terminal。我太懶,所以只好把KDE中的konsole借來用用了。好在KDE程序在gnome中也可以正常運行。下面是經過我折騰后的Fedora 20:
有人說,GTK+程序的列表兩行之間的寬度大到可以塞進一頭大象。以前在Ubuntu下用Eclipse不覺得,換到Fedora中發(fā)現(xiàn)這個寬度確實是挺大的,看著很不舒服。不過這都不是個事,換個GTK+的theme一切都搞定。下面一張是Eclipse的截圖,還是很漂亮的說:
下面開始今天的正題。
結構化數據
結構化數據可不是我一拍腦袋想出來的術語。平時我們在組織和保存數據的時候,離不開數據結構。我們經常使用的數組、鏈表或多維數組來保存數據,也經常使用數據庫的表格保存數據,但是我們并不是時時刻刻想著結構化這么一個概念。但是在Eclipse中就不一樣了,結構化數據是它的一個很重要的理念,只要有可能,它都會把數據組織成結構化的。比如,如果你在Eclipse中選擇了一些什么,那么這些選擇的東西就是以IStructuredSelection展示出來的。如下圖,可見Structured無處不在:
數組(包括鏈表)、樹和表格(包括多維數組)是我們常用的數據結構。List控件、Tree控件和Table控件是我們常用的展示數據的控件。然而邏輯和形式并不總是一一對應的。比如形式上可以用Tree控件表現(xiàn)的數據,邏輯上并不一定是用樹結構組織起來的數據。想想我們做數據庫的ORM映射,如果一個表中的一行數據和另一個表中的多行數據相關聯(lián)(一對多映射),寫成Java Entity類的時候就是一個Entity中包含有一個另一個Entity的List或Set。這兩個Entity各有各的Class Name,而不是統(tǒng)一叫TreeNode。這兩個Entity之間也不用getParent和getChildren互相訪問。但是從形式上,依然可以用一個Tree控件來展示它們,不是嗎?
JFace中的Viewer
在該系列博文的第02篇中,我展示了SWT的List控件和Tree控件。這兩個控件的使用是很簡單的,List控件只需要使用add()方法就可以在列表中添加一個字符串,Tree控件需要先構造一個TreeItem對象,然后用setText()方法添加一個字符串。控件只能用來顯示字符串和字符串前面的一個小圖標,不能保存復雜的數據。MVC是常用的設計模式,Model用來保存數據,而控件只是負責顯示,所以中間一定要有一個機制將Model中的數據轉換為能讓控件顯示的字符串和圖標,并且要能維持數據在結構化上的邏輯聯(lián)系。
JFace中的Viewer是對SWT中的控件的封裝,它使用的正是MVC模式。如果不了解Viewer的哲學,使用Viewer就無從下手。Viewer的哲學是這樣的:Viewer對它要顯示的數據是怎么組織的沒有任何要求,可以使用它的setInput()方法將任何一個對象作為它的Model;很顯然Viewer不可能智能到顯示任何結構的數據,所以必須給它提供一個ContentProvider,ContentProvider就是負責將任意類型的Model轉化為結構化的數據;Model經過ContentProvider轉化為結構化數據后,Viewer再對該結構中的每一項進行顯示,前面提到過控件只能顯示文字和圖片,所以還需要一個LabelProvider來將數據轉化成要顯示的文字和圖片。
由上面的描述可以看出,要使用Viewer必須最少編寫三樣東西:一些Model、一個ContentProvider和一個LabelProvider。當然,Viewer還有更多的功能,比如對數據進行排序和過濾,只需要提供相應的SortProvider和FilterProvider即可,但這兩個Provider不是必須的。雖然要寫的類比較多,但是JFace都定義好了Interface,我們只需要實現(xiàn)即可,在IDE的幫助下,這個工作一點也不難。
一個簡單的示例
文字內容寫得再多,也不如一個例子來得直接。我這里模擬HIS(Hospital Information System)系統(tǒng)中一個簡單的功能來展示Viewer的用法。在醫(yī)院里,一個住院部(Inpatient Department)可以有很多個科室(Department),比如內科、外科、五官科等,一個科室里面可以有很多個病人(Patient)。很顯然,這些數據用一個TreeViewer顯示是再合適不過了。先看看這個示例程序界面的總體框架,如下圖:
這只是一個框架,結合上面的界面,我簡要說說我要實現(xiàn)的功能:
1、最左邊的視圖使用了一個TreeViewer,用來顯示住院部的所有科室和病人;
2、工具欄有兩個按鈕,如果最左邊的視圖中被選擇的對象是科室,則帶加號的按鈕可用,其功能是為該科室增加一個病人;如果最左邊的視圖中被選擇的對象是病人,則帶減號的按鈕可用,其功能是刪除這個病人;
3、中間的視圖使用一個TableViewer控件,當最左邊的視圖中被選擇的對象是科室時,則以表格的形式顯示該科室所有病人的詳細信息,每一行代表一個病人;
4、最右邊的視圖使用一個ListViewer控件,僅僅顯示當前選擇的內容。
為示例程序準備數據
該示例程序用到的數據是一個住院部有多個科室、一個科室有多個病人,很顯然這是一個典型的一對多的關系。所以我們的Model需要三個類:Inpatient、Department、Patient。其關系如下:
其中的Gender是一個枚舉。下面是它們的代碼:
Gender.java
package
com.xkland.examples.rcp.minihis.models;
public
enum
Gender
{
MALE,FEMALE;
}
Inpatient.java
package
com.xkland.examples.rcp.minihis.models;
public
class
Inpatient
{
//
住院部
private
Department[] departments;
public
Department[] getDepartments()
{
return
departments;
}
public
Inpatient()
{
departments
=
new
Department[
4
];
departments[
0
]
=
new
Department(
"
內科
"
);
departments[
1
]
=
new
Department(
"
外科
"
);
departments[
2
]
=
new
Department(
"
婦產科
"
);
departments[
3
]
=
new
Department(
"
兒科
"
);
}
}
Department.java
package
com.xkland.examples.rcp.minihis.models;
import
java.util.LinkedList;
import
java.util.List;
public
class
Department
{
private
String name;
private
List
<
Patient
>
patients;
public
Department(String name)
{
super
();
this
.name
=
name;
patients
=
new
LinkedList
<
Patient
>
();
}
public
String getName()
{
return
name;
}
public
void
setName(String name)
{
this
.name
=
name;
}
public
List
<
Patient
>
getPatients()
{
return
patients;
}
public
void
addPatient(Patient patient)
{
patients.add(patient);
}
}
Patient.java
package
com.xkland.examples.rcp.minihis.models;
public
class
Patient
{
//
病人信息,id代表床號
private
int
id;
private
String name;
private
Gender gender;
private
int
age;
private
Department department;
public
Patient(
int
id, String name, Gender gender,
int
age, Department department)
{
super
();
this
.id
=
id;
this
.name
=
name;
this
.gender
=
gender;
this
.age
=
age;
this
.department
=
department;
}
public
int
getId()
{
return
id;
}
public
void
setId(
int
id)
{
this
.id
=
id;
}
public
String getName()
{
return
name;
}
public
void
setName(String name)
{
this
.name
=
name;
}
public
Gender getGender()
{
return
gender;
}
public
void
setGender(Gender gender)
{
this
.gender
=
gender;
}
public
int
getAge()
{
return
age;
}
public
void
setAge(
int
age)
{
this
.age
=
age;
}
public
Department getDepartment()
{
return
department;
}
public
void
setDepartment(Department department)
{
this
.department
=
department;
}
}
然后,創(chuàng)建一個PatientView類,在里面使用一個TreeViewer控件,創(chuàng)建一個Inpatient類的實例,然后添加一點點測試數據,然后把Inpatient的實例作為viewer的input即可。如下圖:
當然,如果沒有設置好ContentProvider和LabelProvider,數據是不可能正常顯示的。所以我們還需要創(chuàng)建一個PatientContentProvider類和PatientLabelProvider類。好在JFace中有早就定義好的接口,我們只需要從這些接口實現(xiàn)即可,如下圖:
我們先來看PatientContentProvider需要實現(xiàn)哪些方法,如下圖,可以看出IDE已經自動把框架搭建起來了,我們只需要填空即可(下圖中的空是我已經填好了的):
第一個要實現(xiàn)的方法是getElements,該方法要求我們把Input的數據轉化成一個Object數組返回。在這個例子中,Input進來的是Inpatient類的對象,所以只需要先將inputElement轉型為Inpatient,然后返回它里面的Department數組即可。第二個要實現(xiàn)的方法是hasChildren,在本例中,如果element是Department,則它就有children,如果是Patient就沒有children。最后要實現(xiàn)的一對方法就是getChildren和getParent,很顯然,如果element是Department,則它的children是它里面保存的List<Patient>,不過返回的時候要把它轉化成數組,如果element是Patient,則它的parent是它的department。So easy!不是嗎?
而PatientLabelProvider的實現(xiàn)就更簡單了,如下圖:
看圖填空,我們只需要完成getText方法和getImage方法即可。邏輯也很簡單,就是判斷element是Department還是Patient,然后分別返回相應的字符串和圖片即可。在這里,我還故意把不同的性別顯示為不同的圖標。有了截圖,我就不貼代碼了。
俗話說一通百通,使用不同的Model和Viewer,就給它不同的ContentProvider和LabelProvider即可。
處理Selection事件
關于數據的展示,我們輕松搞定。不過這還不算完,還有工作要做。現(xiàn)在數據顯示出來了,我們就可以用鼠標來點擊,來選擇。那么我們選擇的數據怎么樣來影響我們程序的行為呢?在前面幾篇對GUI的探討中我說過,程序和用戶的交互是通過事件處理來進行的。也就是說,當我們選擇了Viewer中的一項或多項的時候,Viewer應該發(fā)送一個Selection事件,我們向程序中注冊一個SelectionListener就應該可以捕獲到這個事件。
為了讓patientViewer向程序發(fā)送Selection事件,我們需要讓它成為程序的selectionProvider。通過在PatientView中添加如下一行代碼(最后一行):
有了發(fā)送Selection事件的源,接著應該有接受Selection事件的Listener。先從最簡單的功能做起。最右邊的視圖只是用來顯示所選擇的對象,所以從它先開始。最右邊的視圖類是SelectionView,里面用了一個ListViewer,在這里,我們先讓SelectionView實現(xiàn)ISelectionListener接口,然后把它注冊到Workbench中。如下圖,關鍵代碼我把它標出來了:
selectionChanged()方法將在有目標被選中的時候調用,該方法的實現(xiàn)也很簡單,就是把selection作為ListViewer的input,讓它顯示即可。而要使用ListViewer,我們又得為它提供一個ContentProvider和一個LabelProvider。下面是ContentProvider和LabelProvider的實現(xiàn),也很簡單,這次ContentProvider實現(xiàn)了IStructuredContentProvider接口,而且從代碼中可以看出,selection是一個IStructuredSelection,哪怕我們只選中一項,它也是Structured的。
做好之后,運行程序是這樣的效果:
然后再來實現(xiàn)中間那個視圖DepartmentDetailView的功能。在這個視圖中使用了一個TableViewer。使用TableViewer比使用ListViewer和TreeViewer要稍微復雜一點,因為需要我們自己添加表格的列,并設置表格的屬性。和SelectionView一樣,DepartmentDetailView實現(xiàn)ISelectionListener,并把自己注冊到Workbench中。代碼如下:
TableViewer依然需要一個ContentProvider和一個LabelProvider,不過沒有ITableContentProvider,因為TableViewer是把每一行當成一個element,所以它只需要和ListViewer一樣的ContentProvider即可。但是TableViewer需要的LabelProvider不一樣,要實現(xiàn)ITableLabelProvider,在這里,TableViewer才處理不同的列。如下圖:
完成后,運行程序是這樣的效果:
根據用戶的選擇決定工具欄按鈕是否可用
終于進入今天的最后一個議題了。 在前面的幾篇中,我陸續(xù)用過主菜單、視圖工具欄,今天用到了主工具欄。菜單和工具欄是GUI程序產生命令的主要方式,還有就是快捷鍵和彈出菜單。在Eclipse中,它們的本質都一樣,都是通過關聯(lián)到一個command和一個handler來實現(xiàn)其功能,通過一個menuContribution來指定它們的位置。在今天的示例中,我把menuContribution的locationURI設置為toolbar:org.eclipse.ui.main.toolbar,所以這兩個按鈕就出現(xiàn)在了主工具欄中。如下圖:
在今天的示例中加入工具欄按鈕可不是為了將工具欄。今天的主題是結構化數據。StructuredSelection也是結構化的數據。所以在這個示例中加入工具欄是為了展示用戶選擇的數據會對工具欄按鈕的行為產生影響。從功能上講,我們希望當用戶選擇一個科室的時候,添加病人的按鈕可用,而選擇多個科室或選擇一個或多個病人的時候,添加病人工具欄不可用,希望當用戶選擇一個病人的時候,刪除病人按鈕可用,而當選擇科室或多個病人的時候,刪除按鈕不可用。
這樣的需求在GUI編程中可以算是無處不在。Eclipse RCP是如何處理這個問題的呢?答案就是Workbench Core Expressions。下圖是Eclipse幫助文檔中關于Workbench Core Expressions的頁面:
然后,我們只需要對工具欄的按鈕添加如下的Workbench Core Expressions即可:
收工,今天就寫到這里。這篇文章已經夠長了,截圖也有20多張了,所以實現(xiàn)那兩個按鈕的Handler我就不寫了。理解了結構化數據和理解了IStructuredSelection后,理解Workbench Core Expression就很容易了,更詳細的內容大家自己看幫助文檔吧。
寫到這里,Eclipse RCP的大部分UI元素如窗口、菜單、工具欄、視圖等等什么的都提到了,還有一個很重要的大件的UI building block就是編輯器了。等下次有時間,我再來詳細討論編輯器的編寫。
評論
#
re: Eclipse RCP詳解(05):JFace和結構化數據
回復
更多評論
2014-04-19 10:01 by
bimbashi
期待博主更新,另外能否說一下windowbuilder,jfreechart等在RCP里面怎么用,他們與e4 tools的關系等。
#
re: Eclipse RCP詳解(05):JFace和結構化數據
回復
更多評論
2014-12-21 01:32 by
當當爸
看到博主在博客園的Linux系列了,想留言需要注冊就作罷,希望博主繼續(xù)Eclipse RCP系列啊
#
re: Eclipse RCP詳解(05):JFace和結構化數據
回復
更多評論
2014-12-21 20:00 by
當當爸
設置visibleWhen后,RCP啟動后工具欄顯示不出來,是否應該在handler處設置enableWhen,我這樣設置后可以
#
re: Eclipse RCP詳解(05):JFace和結構化數據
回復
更多評論
2014-12-21 20:16 by
當當爸
另外,想問一下博主,你的圖片都是自己畫的嗎?用什么工具畫的?
#
re: Eclipse RCP詳解(05):JFace和結構化數據[未登錄]
回復
更多評論
2014-12-22 21:35 by
京山游俠
@當當爸
是要繼續(xù)Eclipse RCP系列的,中途因為準備碩士論文和參加答辯,然后從5月份又開始寫Linux系列所以就停了。
至于畫圖,我用的Dia。在我的Linux系列中,有一篇就是專門介紹繪圖軟件的。
#
re: Eclipse RCP詳解(05):JFace和結構化數據
回復
更多評論
2015-01-09 09:13 by
家電維修
博主的幾篇Eclipse RCP系列文章都很精彩,繼續(xù)支持博主。
新用戶注冊
刷新評論列表
只有注冊用戶
登錄
后才能發(fā)表評論。
網站導航:
博客園
IT新聞
Chat2DB
C++博客
博問
管理
相關文章:
Eclipse RCP詳解(05):JFace和結構化數據
Eclipse RCP詳解(04):Eclipse RCP相關的學習資料及國內相關圖書點評
Eclipse RCP詳解(03):SWT的相關概念以及一個連連看游戲的實現(xiàn)
Eclipse RCP詳解(02):Eclipse的Runtime和UI初探
Eclipse RCP詳解(01):Hello World以及Eclipse RCP和OSGi的簡單展示
使用Eclipse RCP進行桌面程序開發(fā)(六):向OpenGL進軍
使用Eclipse RCP進行桌面程序開發(fā)(五):2D繪圖
使用Eclipse RCP進行桌面程序開發(fā)(四):在Windows中使用Active X控件
使用Eclipse RCP進行桌面程序開發(fā)(三):視圖和透視圖
使用Eclipse RCP進行桌面程序開發(fā)(二):菜單、工具欄和對話框
Powered by:
BlogJava
Copyright © 京山游俠
日歷
<
2014年3月
>
日
一
二
三
四
五
六
23
24
25
26
27
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
常用鏈接
我的隨筆
我的評論
我的參與
最新評論
留言簿
(72)
給我留言
查看公開留言
查看私人留言
隨筆分類
J2EE學習及探索(3)
Linux和Java(4)
NetBeans與J2ME(5)
SpringSide開發(fā)實戰(zhàn)(24)
SVN與源代碼管理(3)
擁抱Eclipse RCP(11)
隨筆檔案
2014年3月 (1)
2014年2月 (2)
2014年1月 (2)
2013年12月 (1)
2009年8月 (1)
2009年7月 (6)
2009年4月 (3)
2009年3月 (1)
2008年12月 (4)
2008年11月 (1)
2008年3月 (1)
2008年2月 (2)
2008年1月 (1)
2007年12月 (1)
2007年10月 (3)
2007年8月 (3)
2007年7月 (2)
2007年3月 (3)
2007年1月 (2)
2006年12月 (5)
2006年11月 (4)
2006年9月 (1)
收藏夾
我常用的技術資料(7)
我的博客系列
我的 .net 博客
我的 c++ 博客
搜索
積分與排名
積分 - 657445
排名 - 73
最新評論
1.?re: SpringSide 3 中的安全框架
通俗易懂,謝謝樓主
--薄荷檸檬草
2.?re: 淺論Maven和Git的原理及展示其與Eclipse的集成
就是單純的表示下 感謝! 入門階段看了很多介紹 從你這里收貨最大!多謝!
--laowang
3.?re: 使用Eclipse RCP進行桌面程序開發(fā)(六):向OpenGL進軍[未登錄]
10年過去了。。
--pass86
4.?re: SpringSide 3 中的安全框架
樓主的文章果然講的好清晰,謝謝分享
--匿
5.?re: 淺論Maven和Git的原理及展示其與Eclipse的集成
評論內容較長,點擊標題查看
--zuidaima
閱讀排行榜
1.?使用Eclipse RCP進行桌面程序開發(fā)(一):快速起步(69804)
2.?SpringSide 3 中的安全框架(65742)
3.?使用Eclipse RCP進行桌面程序開發(fā)(二):菜單、工具欄和對話框(36549)
4.?使用Eclipse RCP進行桌面程序開發(fā)(三):視圖和透視圖(33512)
5.?SpringSide開發(fā)實戰(zhàn)(一):使用Eclipse讓SpringSide跑起來(31500)
評論排行榜
1.?使用Eclipse RCP進行桌面程序開發(fā)(一):快速起步(54)
2.?SpringSide開發(fā)實戰(zhàn)(七):在項目中整合FCKeditor(42)
3.?使用Eclipse RCP進行桌面程序開發(fā)(三):視圖和透視圖(40)
4.?SpringSide 3 的進步(33)
5.?使用Eclipse RCP進行桌面程序開發(fā)(二):菜單、工具欄和對話框(30)
主站蜘蛛池模板:
亚洲无码一区二区三区
|
亚洲码欧美码一区二区三区
|
亚洲精品视频免费观看
|
亚洲男人的天堂一区二区
|
污网站免费在线观看
|
亚洲熟伦熟女新五十路熟妇
|
一二三四在线观看免费高清中文在线观看
|
久草免费在线观看视频
|
亚洲日韩中文字幕天堂不卡
|
亚洲免费福利在线视频
|
亚洲成a人片在线观
|
成年女人18级毛片毛片免费观看
|
亚洲AV无码专区在线观看成人
|
亚洲AV无码资源在线观看
|
又黄又爽无遮挡免费视频
|
人成免费在线视频
|
亚洲香蕉成人AV网站在线观看
|
免费在线观看一级片
|
亚洲国产综合在线
|
国产美女无遮挡免费视频
|
一日本道a高清免费播放
|
亚洲国产成人高清在线观看
|
3344永久在线观看视频免费首页
|
亚洲一区二区三区四区视频
|
在线视频免费观看www动漫
|
国产亚洲精彩视频
|
亚洲不卡av不卡一区二区
|
69天堂人成无码麻豆免费视频
|
亚洲日韩久久综合中文字幕
|
久久精品亚洲男人的天堂
|
免费观看激色视频网站bd
|
老外毛片免费视频播放
|
久久亚洲AV午夜福利精品一区
|
无码中文在线二区免费
|
精品国产免费一区二区三区
|
亚洲一区二区三区无码国产
|
亚洲另类少妇17p
|
国产精品1024永久免费视频
|
高潮毛片无遮挡高清免费视频
|
少妇中文字幕乱码亚洲影视
|
免费在线黄色网址
|