OSDN Git Service

重複するコードを整理。
[tpi/lychee.git] / src / lychee / frm_main.cpp
1 /*******************************************************************************\r
2   TPI - flexible but useless plug-in framework.\r
3   Copyright (C) 2002-2009 Silky\r
4 \r
5   This library is free software; you can redistribute it and/or modify it under\r
6   the terms of the GNU Lesser General Public License as published by the Free\r
7   Software Foundation; either version 2.1 of the License, or (at your option)\r
8   any later version.\r
9 \r
10   This library is distributed in the hope that it will be useful, but WITHOUT\r
11   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or \r
12   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License\r
13   for more details.\r
14 \r
15   You should have received a copy of the GNU Lesser General Public License along\r
16   with this library; if not, write to the Free Software Foundation, Inc.,\r
17   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
18 \r
19   $Id$\r
20 *******************************************************************************/\r
21 \r
22 #include "lychee.h"\r
23 \r
24 #include "frm_main.h"\r
25 #include "cls_filedroptarget.h"\r
26 #include "dlg_make.h"\r
27 #include "dlg_process.h"\r
28 #include "functions.h"\r
29 \r
30 #include <wx/arrimpl.cpp>\r
31 \r
32 WX_DEFINE_OBJARRAY(ArrayTPI_FILEINFO);\r
33 \r
34 #define SetMenuToolState(id, state) this->toolbar->EnableTool(XRCID(id), state); this->menubar->Enable(XRCID(id), state)\r
35 \r
36 //******************************************************************************\r
37 //    グローバル変数\r
38 //******************************************************************************\r
39 \r
40 wxImageList g_hIconT(16, 16), g_hIconLL(32, 32), g_hIconLS(16, 16);\r
41 int g_nSortColumn;\r
42 bool g_fSortAscend;\r
43 \r
44 //******************************************************************************\r
45 // MainFrame\r
46 //******************************************************************************\r
47 \r
48 MainFrame::MainFrame(): wxFrame(), gFrame(NULL)\r
49 {\r
50 }\r
51 \r
52 MainFrame::~MainFrame()\r
53 {\r
54         // 設定を記録。\r
55         if (! this->IsIconized() && ! this->IsMaximized())\r
56         {\r
57                 int a, b;\r
58                 this->GetSize(& a, & b);\r
59                 this->conf.WriteId(CONF_WINDOW_WIDTH,  a);\r
60                 this->conf.WriteId(CONF_WINDOW_HEIGHT, b);\r
61                 this->GetPosition(& a, & b);\r
62                 this->conf.WriteId(CONF_WINDOW_X, a);\r
63                 this->conf.WriteId(CONF_WINDOW_Y, b);\r
64         }\r
65         this->conf.WriteId(CONF_WINDOW_SPLITTER_POS, this->window_splitter->GetSashPosition());\r
66 \r
67         // ツールバー/ステータスバー関連。\r
68         this->conf.WriteId(CONF_WINDOW_STATUSBAR, this->statusbar->IsShown());\r
69         this->conf.WriteId(CONF_WINDOW_TOOLBAR,   this->toolbar->IsShown());\r
70 \r
71         // ListView関連。\r
72         this->conf.WriteId(CONF_LISTVIEW_SHOWMODE, this->menubar->IsChecked(XRCID("Exe_View_Icons")) ? 1 : this->menubar->IsChecked(XRCID("Exe_View_List")) ? 2 : 0);\r
73         if (this->menubar->IsChecked(XRCID("Exe_View_Details")))\r
74         {\r
75                 this->conf.WriteId(CONF_LISTVIEW_C_FILENAME, this->list_ctrl->GetColumnWidth(0));\r
76                 this->conf.WriteId(CONF_LISTVIEW_C_UNPACKED, this->list_ctrl->GetColumnWidth(1));\r
77                 this->conf.WriteId(CONF_LISTVIEW_C_PACKED,   this->list_ctrl->GetColumnWidth(2));\r
78                 this->conf.WriteId(CONF_LISTVIEW_C_RATIO,    this->list_ctrl->GetColumnWidth(3));\r
79                 this->conf.WriteId(CONF_LISTVIEW_C_METHOD,   this->list_ctrl->GetColumnWidth(4));\r
80                 this->conf.WriteId(CONF_LISTVIEW_C_ATTR,         this->list_ctrl->GetColumnWidth(5));\r
81                 this->conf.WriteId(CONF_LISTVIEW_C_LASTMOD,  this->list_ctrl->GetColumnWidth(6));\r
82                 this->conf.WriteId(CONF_LISTVIEW_C_PATH,     this->list_ctrl->GetColumnWidth(7));\r
83                 this->conf.WriteId(CONF_LISTVIEW_C_TYPE,     this->list_ctrl->GetColumnWidth(8));\r
84                 this->conf.WriteId(CONF_LISTVIEW_C_NO,       this->list_ctrl->GetColumnWidth(9));\r
85                 this->conf.WriteId(CONF_LISTVIEW_C_COMMENT,  this->list_ctrl->GetColumnWidth(10));\r
86                 this->conf.WriteId(CONF_LISTVIEW_S_COLUMN,   g_nSortColumn);\r
87                 this->conf.WriteId(CONF_LISTVIEW_S_ASCEND,   g_fSortAscend);\r
88         }\r
89 \r
90         wxCommandEvent e;\r
91         delete this->gFrame;\r
92         this->Show(false);\r
93         this->OnArcClose(e);\r
94 }\r
95 \r
96 //******************************************************************************\r
97 // Event Table.\r
98 //******************************************************************************\r
99 \r
100 BEGIN_EVENT_TABLE(MainFrame, wxFrame)\r
101         EVT_INIT_DIALOG(MainFrame::OnInit)\r
102         EVT_SIZE(       MainFrame::OnSize)\r
103         EVT_CLOSE(      MainFrame::OnClose)\r
104         // Menu\r
105         EVT_MENU(XRCID("Arc_Create"),  MainFrame::OnArcCreate)\r
106         EVT_MENU(XRCID("Arc_Open"),    MainFrame::OnArcOpen)\r
107         EVT_MENU(XRCID("Arc_Close"),   MainFrame::OnArcClose)\r
108         EVT_MENU(XRCID("Arc_Clone"),   MainFrame::OnArcClone)\r
109         EVT_MENU(XRCID("Arc_Add"),     MainFrame::OnArcAdd)\r
110         EVT_MENU(XRCID("Arc_SFX"),     MainFrame::OnArcConvert)\r
111         EVT_MENU(XRCID("Arc_UnSFX"),   MainFrame::OnArcConvert)\r
112         EVT_MENU(XRCID("Exe_Exit"),    MainFrame::OnExit)\r
113         EVT_MENU(XRCID("Arc_Extract"), MainFrame::OnArcExtract)\r
114         EVT_MENU(XRCID("Arc_Delete"),  MainFrame::OnArcDelete)\r
115         EVT_MENU(XRCID("Arc_Test"),    MainFrame::OnArcTest)\r
116         EVT_MENU(XRCID("Arc_Repair"),  MainFrame::OnArcRepair)\r
117         EVT_MENU(XRCID("Exe_Copy"),    MainFrame::OnExeCopy)\r
118         EVT_MENU(XRCID("Exe_View_Icons"),  MainFrame::OnViewMode)\r
119         EVT_MENU(XRCID("Exe_View_Details"),MainFrame::OnViewMode)\r
120         EVT_MENU(XRCID("Exe_View_List"),   MainFrame::OnViewMode)\r
121         EVT_MENU(XRCID("Exe_View_ToolBar"),MainFrame::OnShowToolBar)\r
122         EVT_MENU(XRCID("Exe_View_StatusBar"),MainFrame::OnShowStatusBar)\r
123         EVT_MENU(XRCID("Exe_View_SelectAll"),MainFrame::OnSelectAll)\r
124         // TreeView\r
125         EVT_TREE_SEL_CHANGED(XRCID("TreeView"), MainFrame::OnTreeChanged)\r
126         EVT_TREE_BEGIN_DRAG( XRCID("TreeView"), MainFrame::OnTreeBeginDrag)\r
127         EVT_COMMAND_CONTEXT_MENU(XRCID("TreeView"), MainFrame::OnContextMenu)\r
128         // ListView\r
129         EVT_LIST_ITEM_SELECTED(  XRCID("ListView"), MainFrame::OnListItemSelect)\r
130         EVT_LIST_ITEM_DESELECTED(XRCID("ListView"), MainFrame::OnListItemSelect)\r
131         EVT_LIST_ITEM_ACTIVATED( XRCID("ListView"), MainFrame::OnListItemDClick)\r
132         EVT_LIST_BEGIN_DRAG(     XRCID("ListView"), MainFrame::OnListBeginDrag)\r
133         EVT_COMMAND_CONTEXT_MENU(XRCID("ListView"), MainFrame::OnContextMenu)\r
134         // Filter\r
135         EVT_TEXT(XRCID("tcFilter"), MainFrame::OnFilter)\r
136 END_EVENT_TABLE()\r
137 \r
138 //******************************************************************************\r
139 // Event handler.\r
140 //******************************************************************************\r
141 \r
142 void MainFrame::OnInit(wxInitDialogEvent&)\r
143 {\r
144         // XRCと結びつけ。\r
145         this->menubar    = this->GetMenuBar();\r
146         this->toolbar    = this->GetToolBar();\r
147         this->statusbar = XRCCTRL(* this, "statusbar", wxStatusBar);\r
148         this->tree_ctrl = XRCCTRL(* this, "TreeView", wxTreeCtrl);\r
149         this->list_ctrl = XRCCTRL(* this, "ListView", myListCtrl);\r
150         this->window_splitter = XRCCTRL(* this, "window_splitter", wxSplitterWindow);\r
151         this->tcFilter  = XRCCTRL(* this->toolbar, "tcFilter", wxTextCtrl);\r
152 \r
153         // 設定を読み込み。\r
154         this->SetSize(this->conf.ReadId(CONF_WINDOW_X, 0l), this->conf.ReadId(CONF_WINDOW_Y, 0l), this->conf.ReadId(CONF_WINDOW_WIDTH, 800l), this->conf.ReadId(CONF_WINDOW_HEIGHT, 400l), wxSIZE_ALLOW_MINUS_ONE);\r
155         wxTheMimeTypesManager->Initialize(wxMAILCAP_ALL);\r
156 \r
157         // 初期値設定。\r
158         {\r
159                 wxIcon icon;\r
160                 icon.CopyFromBitmap(wxBitmap(L_DIR_S_ICO wxT("app.png"), wxBITMAP_TYPE_ANY));\r
161                 this->SetIcon(icon);\r
162         }\r
163         wxCommandEvent e;\r
164         this->OnArcClose(e);\r
165         this->SetDropTarget(new myFileDropTarget(this));\r
166 \r
167         // スプリッター設定。\r
168         this->window_splitter->SetSashPosition(this->conf.ReadId(CONF_WINDOW_SPLITTER_POS, 200l));\r
169 \r
170         // リストビュー設定。\r
171         int nIconMode = this->conf.ReadId(CONF_LISTVIEW_SHOWMODE, 0l);\r
172         e.SetId(nIconMode == 1 ? XRCID("Exe_View_Icons") : (nIconMode == 2 ? XRCID("Exe_View_List") : XRCID("Exe_View_Details")));\r
173         this->OnViewMode(e);\r
174         // wxGTKでは直接wxLC_VIRTUALを指定しないと反映されない。\r
175         this->list_ctrl->SetSingleStyle(wxLC_VIRTUAL);\r
176         this->list_ctrl->InsertColumn(0, _("Filename"),      wxLIST_FORMAT_LEFT,   this->conf.ReadId(CONF_LISTVIEW_C_FILENAME, 140l));\r
177         this->list_ctrl->InsertColumn(1, _("Unpacked"),      wxLIST_FORMAT_RIGHT,  this->conf.ReadId(CONF_LISTVIEW_C_UNPACKED,  80l));\r
178         this->list_ctrl->InsertColumn(2, _("Packed"),        wxLIST_FORMAT_RIGHT,  this->conf.ReadId(CONF_LISTVIEW_C_PACKED,    80l));\r
179         this->list_ctrl->InsertColumn(3, _("Ratio"),         wxLIST_FORMAT_RIGHT,  this->conf.ReadId(CONF_LISTVIEW_C_RATIO,     50l));\r
180         this->list_ctrl->InsertColumn(4, _("Method"),        wxLIST_FORMAT_LEFT,   this->conf.ReadId(CONF_LISTVIEW_C_METHOD,    60l));\r
181         this->list_ctrl->InsertColumn(5, _("Attr"),          wxLIST_FORMAT_LEFT,   this->conf.ReadId(CONF_LISTVIEW_C_ATTR,      50l));\r
182         this->list_ctrl->InsertColumn(6, _("Last modified"), wxLIST_FORMAT_RIGHT,  this->conf.ReadId(CONF_LISTVIEW_C_LASTMOD,  150l));\r
183         this->list_ctrl->InsertColumn(7, _("Path"),          wxLIST_FORMAT_LEFT,   this->conf.ReadId(CONF_LISTVIEW_C_PATH,     100l));\r
184         this->list_ctrl->InsertColumn(8, _("Type"),          wxLIST_FORMAT_LEFT,   this->conf.ReadId(CONF_LISTVIEW_C_TYPE,     100l));\r
185         this->list_ctrl->InsertColumn(9, _("No."),           wxLIST_FORMAT_RIGHT,  this->conf.ReadId(CONF_LISTVIEW_C_NO,        35l));\r
186         this->list_ctrl->InsertColumn(10,_("Comment"),       wxLIST_FORMAT_LEFT,   this->conf.ReadId(CONF_LISTVIEW_C_COMMENT,   35l));\r
187         g_nSortColumn = this->conf.ReadId(CONF_LISTVIEW_S_COLUMN, 9l);\r
188         g_fSortAscend = this->conf.ReadId(CONF_LISTVIEW_S_ASCEND, true);\r
189 \r
190         // ツールバー/ステータスバー設定。\r
191         int nStatusBarParts[] = {70, 70, 180, 50, -1};\r
192         this->statusbar->SetFieldsCount(5, nStatusBarParts);\r
193         this->SetStatusBarPane(-1);\r
194         bool fShow = this->conf.ReadId(CONF_WINDOW_STATUSBAR, true);\r
195         this->menubar->Check(XRCID("Exe_View_StatusBar"), fShow);\r
196         this->statusbar->Show(fShow);\r
197         fShow = this->conf.ReadId(CONF_WINDOW_TOOLBAR, true);\r
198         this->menubar->Check(XRCID("Exe_View_ToolBar"), fShow);\r
199         this->toolbar->Show(fShow);\r
200 \r
201         // ステータスバー上にプログレスバーを作成。\r
202         this->gFrame = new wxGauge(this, -1, 0, wxPoint(0, 0), wxSize(200, 10));\r
203         this->gFrame->Show(false);\r
204 }\r
205 \r
206 void MainFrame::OnClose(wxCloseEvent& e)\r
207 {\r
208         if (e.CanVeto() && g_procDlg != NULL)\r
209         {\r
210                 g_procDlg->OnClose(e);\r
211                 e.Veto();\r
212         }\r
213         else\r
214         {\r
215                 this->Destroy();\r
216         }\r
217 }\r
218 \r
219 void MainFrame::OnSize(wxSizeEvent& e)\r
220 {\r
221         // ウインドウの内容の位置を変更。\r
222         if (this->window_splitter != NULL)\r
223         {\r
224                 this->window_splitter->SetSize(this->GetClientSize());\r
225         }\r
226 \r
227         // プログレスバーの位置を変更。\r
228         if (this->gFrame != NULL)\r
229         {\r
230                 wxPoint p = this->statusbar->GetPosition();\r
231                 wxSize  s = this->GetSize();\r
232                 p.x += s.GetWidth() - 230;\r
233                 p.y += 10;\r
234                 this->gFrame->SetPosition(p);\r
235         }\r
236         e.Skip();\r
237 }\r
238 \r
239 // MenuBar\r
240 \r
241 void MainFrame::OnExit(wxCommandEvent&)\r
242 {\r
243         this->Close(true);\r
244 }\r
245 \r
246 void MainFrame::OnArcCreate(wxCommandEvent& e)\r
247 {\r
248         TPI_SWITCHES swInfo;\r
249         swInfo.pCustomSwitches = NULL;\r
250 \r
251         // 作成ダイアログを設定。\r
252         MakeDialog mkDlg(this, TPI_COMMAND_CREATE);\r
253         if (e.GetClientData() == NULL)\r
254         {\r
255                 // 処理対象のファイルを選択。\r
256                 wxFileDialog fd(this, _("Choose files to compress"), this->conf.ReadHistory(CONF_HISTORY_PATH, 0), wxEmptyString, wxFileSelectorDefaultWildcardStr, wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);\r
257                 if (fd.ShowModal() == wxID_CANCEL)\r
258                 {\r
259                         return;\r
260                 }\r
261                 swInfo.fnDestinationDirectory = wxFileName::DirName(fd.GetDirectory());\r
262                 this->conf.WriteHistory(CONF_HISTORY_PATH, fd.GetDirectory());\r
263                 fd.GetFilenames(mkDlg.files);\r
264         }\r
265         else\r
266         {\r
267                 mkDlg.files = * (wxArrayString *) e.GetClientData();\r
268                 swInfo.fnDestinationDirectory = wxFileName::DirName(wxFileName(mkDlg.files[0]).GetPath());\r
269                 // 相対パスに変換。\r
270                 for (size_t n = 0; n < mkDlg.files.GetCount(); n++)\r
271                 {\r
272                         wxFileName fn(mkDlg.files[n]);\r
273                         fn.MakeRelativeTo(swInfo.fnDestinationDirectory.GetPath());\r
274                         mkDlg.files[n] = fn.GetFullPath();\r
275                 }\r
276         }\r
277 \r
278         this->OnArcClose(e);\r
279         // 書庫名はファイル名の拡張子より前、もしくはディレクトリ名。\r
280         this->fnArchive = wxFileName(mkDlg.files[0]);\r
281         this->fnArchive.SetName(mkDlg.files.GetCount() == 1 ? (this->fnArchive.GetName().IsEmpty() ? this->fnArchive.GetDirs().Last() : this->fnArchive.GetName()) : swInfo.fnDestinationDirectory.GetDirs().Last());\r
282         this->fnArchive.SetEmptyExt();\r
283         this->fnArchive.SetPath(swInfo.fnDestinationDirectory.GetPath());\r
284 \r
285         // ダイアログを表示。\r
286         if (mkDlg.ShowModal() == wxID_CANCEL)\r
287         {\r
288                 return;\r
289         }\r
290 \r
291         // 各種設定。\r
292         int nSelected = mkDlg.chType->GetSelection();\r
293         swInfo.nArchiveType         = mkDlg.afInfo[nSelected].nTypeId;\r
294         swInfo.fStoreDirectoryPathes= ! mkDlg.cbIgnorePath->IsChecked();\r
295         swInfo.fMakeSFX                     = mkDlg.cbMakeSFX->IsChecked();\r
296         swInfo.fSolid               = mkDlg.cbSolid->IsChecked();\r
297         swInfo.fMMOptimize          = mkDlg.cbMMOptimize->IsChecked();\r
298         swInfo.fEncryptHeader       = mkDlg.cbEncryptHeader->IsChecked();\r
299         swInfo.fCompressHeader      = mkDlg.cbCompressHeader->IsChecked();\r
300         swInfo.nCompressLevel       = mkDlg.scLevel->GetValue();\r
301         swInfo.nRecoveryRecord      = mkDlg.scRR->GetValue();\r
302         swInfo.szPassword           = mkDlg.tcPassword->GetValue();\r
303         swInfo.szKeyFile            = mkDlg.tcKeyfile->GetValue();\r
304         swInfo.szComment            = mkDlg.tcComment->GetValue();\r
305         mkDlg.cbSplitSize->GetValue().ToULongLong(& swInfo.nSplitSize);\r
306 \r
307         // TPIを読み込み。\r
308         this->fnArchive = wxFileName(mkDlg.cbDir->GetValue(), mkDlg.cbFileName->GetValue());\r
309         if (! tpi.InitLibrary(mkDlg.afInfo[nSelected].szTPIName, this->fnArchive.GetFullPath(), TPICallbackProc, mkDlg.afInfo[nSelected].nTypeId))\r
310         {\r
311                 this->ErrorCheck(tpi.nErrorCode, wxT("InitLibrary"));\r
312                 return;\r
313         }\r
314 \r
315         // 処理を行う。\r
316         {\r
317                 ProcessDialog procDlg(this, mkDlg.files.GetCount());\r
318                 tpi.Command(TPI_COMMAND_CREATE, & swInfo, this->fnArchive.GetFullPath(), mkDlg.files);\r
319                 procDlg.Show(false);\r
320                 if (this->ErrorCheck(tpi.nErrorCode) != TPI_ERROR_SUCCESS)\r
321                 {\r
322                         return;\r
323                 }\r
324         }\r
325         tpi.FreeLibrary();\r
326 \r
327         if (mkDlg.cbOpenAfter->IsChecked())\r
328         {\r
329                 // 作成先を開く。\r
330                 ::wxExecute(DIR_APP + QuoteString(swInfo.fnDestinationDirectory.GetFullPath()));\r
331         }\r
332 \r
333         if (mkDlg.cbExitAfter->IsChecked())\r
334         {\r
335                 // 終了。\r
336                 this->Close(true);\r
337         }\r
338 \r
339         // 終了しない場合は書庫を開く。\r
340         if (this->fnArchive.FileExists())\r
341         {\r
342                 this->OnArcOpen(e);\r
343         }\r
344 }\r
345 \r
346 void MainFrame::OnArcOpen(wxCommandEvent& e)\r
347 {\r
348         // モード取得。通常は0, それ以外で開く場合は1, ファイルDnDなら2。\r
349         int nMode = e.GetInt();\r
350 \r
351         // 書庫を選択。\r
352         if (nMode == 0)\r
353         {\r
354                 wxFileDialog fd(this, _("Choose an archive"), this->conf.ReadHistory(CONF_HISTORY_PATH, 0), wxEmptyString, wxFileSelectorDefaultWildcardStr, wxFD_OPEN | wxFD_FILE_MUST_EXIST);\r
355                 if (fd.ShowModal() == wxID_CANCEL)\r
356                 {\r
357                         return;\r
358                 }\r
359                 this->conf.WriteHistory(CONF_HISTORY_PATH, fd.GetDirectory());\r
360                 this->fnArchive = wxFileName(fd.GetPath());\r
361         }\r
362 \r
363         // TPIを読み込み。\r
364         ProcessDialog procDlg(this);\r
365         TPI_PROCESSINFO piInfo;\r
366         piInfo.fiInfo.nUnpackedSize = 0;\r
367         if (! this->LoadTPI(this->fnArchive.GetFullPath(), & piInfo.fiInfo.nUnpackedSize))\r
368         {\r
369                 if (nMode == 2)\r
370                 {\r
371                         // DnDの場合は書庫を作成する。\r
372                         this->OnArcCreate(e);\r
373                 }\r
374                 else if (this->IsShown())\r
375                 {\r
376                         wxBell();\r
377                         this->statusbar->SetStatusText(_("No plug-in supporting this archive was found!"), 4);\r
378                 }\r
379                 else\r
380                 {\r
381                         wxLogError(_("No plug-in supporting this archive was found!"));\r
382                         this->Close(true);\r
383                 }\r
384                 return;\r
385         }\r
386 \r
387         // コマンドラインから書庫を開く場合にはウインドウが表示されていないので表示。\r
388         if (! this->IsShown())\r
389         {\r
390                 this->Show();\r
391         }\r
392 \r
393         piInfo.eMessage = TPI_MESSAGE_STATUS;\r
394         piInfo.eStatus = 0x1001;\r
395         if (this->ErrorCheck(procDlg.CallbackProc(TPI_NOTIFY_COMMON, & piInfo), wxT("Callback")) == TPI_CALLBACK_CANCEL)\r
396         {\r
397                 procDlg.Show(false);\r
398                 tpi.CloseArchive();\r
399                 // OnArcClose処理はProcessDialogのデストラクタで行う。\r
400                 // this->OnArcClose(e);\r
401                 return;\r
402         }\r
403 \r
404         // 配列のサイズを確保。\r
405         this->fileinfo.Alloc(piInfo.fiInfo.nUnpackedSize);\r
406 \r
407         // 履歴に追加。\r
408         this->conf.WriteHistory(CONF_HISTORY_PATH, this->fnArchive.GetPath());\r
409         this->conf.WriteHistory(CONF_HISTORY_NAME, this->fnArchive.GetFullName());\r
410         this->conf.WriteHistory(CONF_HISTORY_FULL, this->fnArchive.GetFullPath());\r
411 \r
412         // 書庫のアイコンを取得し、書庫ルートを作成。\r
413         g_hIconT.Add(wxBitmap(L_DIR_S_ICO wxT("folder_closed.png"), wxBITMAP_TYPE_ANY));\r
414         g_hIconT.Add(wxBitmap(L_DIR_S_ICO wxT("folder_open.png"), wxBITMAP_TYPE_ANY));\r
415         this->tree_ctrl->SetImageList(& g_hIconT);\r
416         wxTreeItemId\r
417                 idRoot    = this->tree_ctrl->AddRoot(wxEmptyString),\r
418                 idArchive = this->tree_ctrl->AppendItem(idRoot, this->fnArchive.GetFullName(), g_hIconT.Add(myRescaleIcon(GetFileTypeIcon(this->fnArchive)))),\r
419                 idArcRoot = this->tree_ctrl->AppendItem(idRoot, wxT("-----"), 0, 1);\r
420 \r
421         // 巨大書庫のときにファイル名検査を省略するか。\r
422         bool bDTVCheck = piInfo.fiInfo.nUnpackedSize < 10000 || ::AskDlg(_("This archive contains so many files that it takes long to check Directory Traversal Vulnerability(DTV) problem. If you are sure this archive is safe, you can skip this scanning process. Do you want to scan for DTV problem?"), this) == wxNO;\r
423 \r
424         // ファイル情報をロード。\r
425         if (tpi.GetFileInformation(& piInfo.fiInfo, true))\r
426         {\r
427                 piInfo.eStatus = 0x1002;\r
428                 piInfo.nProcessedSize = 0;\r
429                 do\r
430                 {\r
431                         piInfo.nProcessedSize++;\r
432                         if (this->ErrorCheck(procDlg.CallbackProc(TPI_NOTIFY_COMMON, & piInfo), wxT("Callback")) == TPI_CALLBACK_CANCEL)\r
433                         {\r
434                                 procDlg.Show(false);\r
435                                 tpi.CloseArchive();\r
436                                 // OnArcClose処理はProcessDialogのデストラクタで行う。\r
437                                 // this->OnArcClose(e);\r
438                                 return;\r
439                         }\r
440 \r
441                         // 拡張子のみ設定されている場合。\r
442                         if (piInfo.fiInfo.szStoredName.IsEmpty())\r
443                         {\r
444                                 piInfo.fiInfo.szStoredName = this->fnArchive.GetName();\r
445                                 if (piInfo.fiInfo.fnFileName.HasExt())\r
446                                 {\r
447                                         piInfo.fiInfo.szStoredName += wxT('.') + piInfo.fiInfo.fnFileName.GetExt();\r
448                                 }\r
449                                 piInfo.fiInfo.fnFileName = wxFileName(piInfo.fiInfo.szStoredName);\r
450                         }\r
451 \r
452                         // セキュリティチェック。\r
453                         // ルート記号を削除。\r
454                         wxString szPath = piInfo.fiInfo.fnFileName.GetPathWithSep(wxPATH_UNIX);\r
455                         if (szPath.StartsWith(wxT("/")) || szPath.StartsWith(wxT("./")))\r
456                         {\r
457                                 piInfo.fiInfo.fnFileName = wxFileName(szPath.AfterFirst(wxT('/')), piInfo.fiInfo.fnFileName.GetFullName(), wxPATH_DOS);\r
458                         }\r
459                         // ルートメンバの情報は無視する。\r
460                         if (piInfo.fiInfo.fnFileName.GetFullPath().IsEmpty() || piInfo.fiInfo.fnFileName.GetFullPath() == wxT("."))\r
461                         {\r
462                                 continue;\r
463                         }\r
464 \r
465                         // 改行文字/タブ文字などを削除。\r
466                         if (piInfo.fiInfo.szStoredName.Find(wxT('\r')) != wxNOT_FOUND\r
467                         ||  piInfo.fiInfo.szStoredName.Find(wxT('\n')) != wxNOT_FOUND\r
468                         ||  piInfo.fiInfo.szStoredName.Find(wxT('\t')) != wxNOT_FOUND)\r
469                         {\r
470                                 wxString sz = piInfo.fiInfo.fnFileName.GetFullPath();\r
471                                 sz.Replace(wxT("\r"), wxT(" "));\r
472                                 sz.Replace(wxT("\n"), wxT(" "));\r
473                                 sz.Replace(wxT("\t"), wxT(" "));\r
474                                 piInfo.fiInfo.eDanger = TRUE;\r
475                                 piInfo.fiInfo.fnFileName = wxFileName(sz);\r
476                                 wxLogWarning(_("This archive may contain files whose name contains some special characters like CR(\\r), LF(\\n), Tab(\\t) and some problem would be happen if you extract these files. Don\'t extract these files carelessly.\nDanger file is:\n%s"), piInfo.fiInfo.fnFileName.GetFullPath().c_str());\r
477                         }\r
478 \r
479                         if (bDTVCheck)\r
480                         {\r
481                                 // DTV検査。\r
482                                 if (piInfo.fiInfo.fnFileName.GetPathWithSep(wxPATH_UNIX).Find(wxT("../")) != wxNOT_FOUND)\r
483                                 {\r
484                                         piInfo.fiInfo.eDanger = TRUE;\r
485                                         wxLogWarning(_("This archive may have Directory Traversal Vulnerability(DTV) problem, and some danger files may be extracted to the unexpected system directory! You should use the \"Ignore file pathes\" option when extracting this archive.\nDanger file is:\n%s"), piInfo.fiInfo.fnFileName.GetFullPath().c_str());\r
486                                 }\r
487                                 // 空白の連続による拡張子偽装を検査。\r
488                                 if (piInfo.fiInfo.fnFileName.GetFullName().Find(wxT("        ")) != wxNOT_FOUND)\r
489                                 {\r
490                                         piInfo.fiInfo.eDanger = TRUE;\r
491                                         wxLogWarning(_("This archive may contain extension-disguised files whose real extension is hidden by using many blank charactor and you may mistake that it is a \"safe\" file. Don\'t execute these files carelessly.\nDanger file is:\n%s"), piInfo.fiInfo.fnFileName.GetFullPath().c_str());\r
492                                 }\r
493                                 // Unicode制御文字を検査。\r
494                                 for (wxChar c = 0x200c; c <= 0x206f; c++)\r
495                                 {\r
496                                         if (piInfo.fiInfo.fnFileName.GetFullName().Find(c) != wxNOT_FOUND)\r
497                                         {\r
498                                                 piInfo.fiInfo.eDanger = TRUE;\r
499                                                 wxLogWarning(_("This archive may contain extension-disguised files whose real extension is hidden by using Unicode control character and you may mistake that it is a \"safe\" file. Don\'t execute these files carelessly.\nDanger file is:\n%s"), piInfo.fiInfo.fnFileName.GetFullPath().c_str());\r
500                                         }\r
501                                         switch (c)\r
502                                         {\r
503                                         case 0x200f: c = 0x2027; break;\r
504                                         case 0x202e: c = 0x2060; break;\r
505                                         }\r
506                                 }\r
507                         }\r
508 \r
509                         // ツリービューに反映。\r
510                         bool fDir = piInfo.fiInfo.dwAttribute & TPI_ATTRIBUTE_DIRECTORY ? true : false;\r
511                         TreeView_CheckNewerItem(this->tree_ctrl, idArcRoot, fDir ? piInfo.fiInfo.fnFileName.GetFullPath() : piInfo.fiInfo.fnFileName.GetPath(), true);\r
512 \r
513                         // ディレクトリ属性を含むものについては情報を保存しない。\r
514                         if (fDir)\r
515                         {\r
516                                 continue;\r
517                         }\r
518 \r
519                         // 情報を保存してカウントアップ。\r
520                         this->fileinfo.Add(piInfo.fiInfo);\r
521                 }\r
522                 while (tpi.GetFileInformation(& piInfo.fiInfo));\r
523         }\r
524 \r
525         // GetFileInformationがエラー終了した場合。\r
526         this->ErrorCheck(tpi.nErrorCode, wxT("GetFileInformation"));\r
527 \r
528         // 書庫の情報を取得。\r
529         tpi.GetArchiveInformation(& this->aiArchive);\r
530         this->ErrorCheck(tpi.nErrorCode, wxT("GetArchiveInformation"));\r
531         this->szPassword = procDlg.szPassword;\r
532 \r
533         // 書庫を閉じる。\r
534         tpi.CloseArchive();\r
535         this->ErrorCheck(tpi.nErrorCode, wxT("CloseArchive"));\r
536 \r
537         // 以下、UI処理。\r
538         this->fileinfo.Shrink();\r
539         if (this->fileinfo.Count() < 10000)\r
540         {\r
541                 this->tree_ctrl->ExpandAll();\r
542                 this->tree_ctrl->SelectItem(idArchive);\r
543         }\r
544         else\r
545         {\r
546                 // ファイル数が多いとソートに時間がかかるので、書庫のルートを表示させる。\r
547                 this->tree_ctrl->Expand(idArcRoot);\r
548                 this->tree_ctrl->SelectItem(idArcRoot);\r
549         }\r
550         // ツリービューの位置合わせ。\r
551         this->tree_ctrl->ScrollTo(idArchive);\r
552         this->tree_ctrl->SetScrollPos(wxHORIZONTAL, 0);\r
553         this->list_ctrl->atDangerItem.SetTextColour(* wxRED);\r
554         this->list_ctrl->atEncryptedItem.SetTextColour(wxColour(wxT("forest green")));\r
555 \r
556         // ステータスバー設定。\r
557         this->statusbar->SetStatusText(this->aiArchive.fiInfo.szTypeName, 0);\r
558         this->statusbar->SetStatusText(wxString::Format(_("%u file(s)"), this->fileinfo.GetCount()), 1);\r
559         this->statusbar->SetStatusText(wxString::Format(wxString("%" wxLongLongFmtSpec "uB -> %" wxLongLongFmtSpec "uB"), this->aiArchive.nUnpackedSize, this->aiArchive.nPackedSize), 2);\r
560         this->statusbar->SetStatusText(wxString::Format(wxT("%3.1f%%"), this->aiArchive.wCompressRatio / 10.0), 3);\r
561         this->statusbar->SetStatusText(this->fnArchive.GetFullPath(), 4);\r
562         this->statusbar->SetToolTip(\r
563                 wxString::Format(\r
564                         _("%s(%s)\nTPI: %s(%s)\nAccess: %s\nModify: %s\nCreate: %s\nComment:\n%s"),\r
565                         this->fnArchive.GetFullName().c_str(), this->aiArchive.fiInfo.szTypeName.c_str(),\r
566                         this->aiArchive.fiInfo.szTPIName.c_str(), this->aiArchive.fiInfo.szEngineName.c_str(),\r
567                         this->aiArchive.tmAccess.Format(_("%Y/%m/%d %H:%M:%S")).c_str(),\r
568                         this->aiArchive.tmModify.Format(_("%Y/%m/%d %H:%M:%S")).c_str(),\r
569                         this->aiArchive.tmCreate.Format(_("%Y/%m/%d %H:%M:%S")).c_str(),\r
570                         this->aiArchive.szComment.c_str()\r
571                 )\r
572         );\r
573 \r
574         // ツールバー・メニューバー設定。ファイル選択時しか動作しない削除などは別に設定。\r
575         SetMenuToolState("Arc_Close",   true);\r
576         SetMenuToolState("Arc_Add",     (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_ADD)    == TPI_COMMAND_ADD   &&   this->aiArchive.fiInfo.fArchive);\r
577         SetMenuToolState("Arc_SFX",     (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_SFX)    == TPI_COMMAND_SFX   && ! this->aiArchive.fSFX);\r
578         SetMenuToolState("Arc_UnSFX",   (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_UNSFX)  == TPI_COMMAND_UNSFX &&   this->aiArchive.fSFX);\r
579         SetMenuToolState("Arc_Extract", (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_EXTRACT)== TPI_COMMAND_EXTRACT);\r
580         SetMenuToolState("Arc_Test",    (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_TEST)   == TPI_COMMAND_TEST);\r
581         SetMenuToolState("Arc_Repair",  (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_REPAIR) == TPI_COMMAND_REPAIR);\r
582         this->menubar->Enable(XRCID("Arc_Clone"), true);\r
583 \r
584         procDlg.Show(false);\r
585         this->Raise();\r
586 }\r
587 \r
588 void MainFrame::OnArcClose(wxCommandEvent& e)\r
589 {\r
590         // ツリービュー・リストビュー設定。\r
591         this->tree_ctrl->DeleteAllItems();\r
592         this->list_ctrl->DeleteAllItems();\r
593         this->list_ctrl->apShowFile.Clear();\r
594 \r
595         // ツールバー・メニューバー設定。\r
596         SetMenuToolState("Arc_Close",   false);\r
597         SetMenuToolState("Arc_Add",     false);\r
598         SetMenuToolState("Arc_SFX",     false);\r
599         SetMenuToolState("Arc_UnSFX",   false);\r
600         SetMenuToolState("Arc_Extract", false);\r
601         SetMenuToolState("Arc_Delete",  false);\r
602         SetMenuToolState("Arc_Test",    false);\r
603         SetMenuToolState("Arc_Repair",  false);\r
604         this->menubar->Enable(XRCID("Arc_Clone"), false);\r
605 \r
606         for (int i = 0; i < this->statusbar->GetFieldsCount(); i++)\r
607         {\r
608                 this->statusbar->SetStatusText(wxEmptyString, i);\r
609         }\r
610         this->statusbar->SetToolTip(wxEmptyString);\r
611         this->fileinfo.Clear();\r
612         this->szPassword.Empty();\r
613         this->aiArchive.szComment.Empty();\r
614         this->aiArchive.fnArchive.Clear();\r
615         this->aiArchive.fiInfo.szTypeName.Empty();\r
616         this->aiArchive.fiInfo.szSuffix.Empty();\r
617         this->aiArchive.fiInfo.szEngineName.Empty();\r
618         this->aiArchive.fiInfo.szTPIName.Empty();\r
619 \r
620         g_hIconT.RemoveAll();\r
621         g_hIconLL.RemoveAll();\r
622         g_hIconLS.RemoveAll();\r
623 \r
624         // DnDで書庫を開くときは既に読み込まれているTPIを用いるので、解放してはいけない。\r
625         if (e.GetExtraLong() == 0)\r
626         {\r
627                 tpi.FreeLibrary();\r
628         }\r
629 }\r
630 \r
631 void MainFrame::OnArcClone(wxCommandEvent&)\r
632 {\r
633         // 保存先を尋ねる。\r
634         wxFileDialog fd(this, _("Clone archive"), this->fnArchive.GetPath(), this->fnArchive.GetFullName(), wxFileSelectorDefaultWildcardStr, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);\r
635         if (fd.ShowModal() == wxID_CANCEL)\r
636         {\r
637                 return;\r
638         }\r
639         this->conf.WriteHistory(CONF_HISTORY_PATH, fd.GetDirectory());\r
640 \r
641         // コピー。\r
642         ::wxCopyFile(this->fnArchive.GetFullPath(), fd.GetPath());\r
643         wxFileName fn(fd.GetPath());\r
644         wxDateTime dtAccess, dtModify, dtCreate;\r
645         this->fnArchive.GetTimes(& dtAccess, & dtModify, & dtCreate);\r
646         fn.SetTimes(& dtAccess, & dtModify, & dtCreate);\r
647 }\r
648 \r
649 void MainFrame::OnArcAdd(wxCommandEvent& e)\r
650 {\r
651         // 作成ダイアログを設定。\r
652         MakeDialog mkDlg(this, TPI_COMMAND_ADD);\r
653 \r
654         TPI_SWITCHES swInfo;\r
655         swInfo.pCustomSwitches       = NULL;\r
656 \r
657         if (e.GetClientData() == NULL)\r
658         {\r
659                 if (::wxGetKeyState(WXK_SHIFT))\r
660                 {\r
661                         // 処理対象のフォルダを選択。\r
662                         wxDirDialog dd(this, _("Choose dir to add"), this->conf.ReadHistory(CONF_HISTORY_PATH, 0), wxDD_DIR_MUST_EXIST);\r
663                         if (dd.ShowModal() == wxID_CANCEL)\r
664                         {\r
665                                 return;\r
666                         }\r
667                         swInfo.fnDestinationDirectory = wxFileName(dd.GetPath());\r
668                         this->conf.WriteHistory(CONF_HISTORY_PATH, swInfo.fnDestinationDirectory.GetPath());\r
669                         mkDlg.files.Add(swInfo.fnDestinationDirectory.GetFullName());\r
670                 }\r
671                 else\r
672                 {\r
673                         // 処理対象のファイルを選択。\r
674                         wxFileDialog fd(this, _("Choose files to add"), this->conf.ReadHistory(CONF_HISTORY_PATH, 0), wxEmptyString, wxFileSelectorDefaultWildcardStr, wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);\r
675                         if (fd.ShowModal() == wxID_CANCEL)\r
676                         {\r
677                                 return;\r
678                         }\r
679                         fd.GetFilenames(mkDlg.files);\r
680                         swInfo.fnDestinationDirectory = wxFileName::DirName(fd.GetDirectory());\r
681                         this->conf.WriteHistory(CONF_HISTORY_PATH, fd.GetDirectory());\r
682                 }\r
683         }\r
684         else\r
685         {\r
686                 mkDlg.files = * (wxArrayString *) e.GetClientData();\r
687                 swInfo.fnDestinationDirectory = wxFileName::DirName(wxFileName(mkDlg.files[0]).GetPath());\r
688                 // 相対パスに変換。\r
689                 for (size_t n = 0; n < mkDlg.files.GetCount(); n++)\r
690                 {\r
691                         wxFileName fn(mkDlg.files[n]);\r
692                         fn.MakeRelativeTo(swInfo.fnDestinationDirectory.GetPath());\r
693                         mkDlg.files[n] = fn.GetFullPath();\r
694                 }\r
695         }\r
696 \r
697         // ダイアログを表示。\r
698         if (mkDlg.ShowModal() == wxID_CANCEL)\r
699         {\r
700                 return;\r
701         }\r
702 \r
703         // 各種設定。\r
704         swInfo.fMakeSFX              = false;\r
705         swInfo.fStoreDirectoryPathes = ! mkDlg.cbIgnorePath->IsChecked();\r
706         swInfo.fSolid               = mkDlg.cbSolid->IsChecked();\r
707         swInfo.fMMOptimize          = mkDlg.cbMMOptimize->IsChecked();\r
708         swInfo.fEncryptHeader       = mkDlg.cbEncryptHeader->IsChecked();\r
709         swInfo.nCompressLevel       = mkDlg.scLevel->GetValue();\r
710         swInfo.nRecoveryRecord      = mkDlg.scRR->GetValue();\r
711         swInfo.szPassword           = mkDlg.tcPassword->GetValue();\r
712         swInfo.szKeyFile            = mkDlg.tcKeyfile->GetValue();\r
713         swInfo.szComment            = mkDlg.tcComment->GetValue();\r
714 \r
715         // 処理を行う。\r
716         {\r
717                 ProcessDialog procDlg(this, mkDlg.files.GetCount(), this->szPassword);\r
718                 tpi.Command(TPI_COMMAND_ADD, & swInfo, this->fnArchive.GetFullPath(), mkDlg.files);\r
719                 this->ErrorCheck(tpi.nErrorCode);\r
720                 procDlg.Show(false);\r
721         }\r
722 \r
723         if (mkDlg.cbOpenAfter->IsChecked())\r
724         {\r
725                 // 作成先を開く。\r
726                 ::wxExecute(DIR_APP + QuoteString(swInfo.fnDestinationDirectory.GetFullPath()));\r
727         }\r
728 \r
729         if (mkDlg.cbExitAfter->IsChecked())\r
730         {\r
731                 // 終了。\r
732                 this->Close(true);\r
733         }\r
734 \r
735         // 終了しない場合は書庫を再読み込み。\r
736         this->OnArcOpen(e);\r
737 }\r
738 \r
739 void MainFrame::OnArcConvert(wxCommandEvent& e)\r
740 {\r
741         TPI_SWITCHES swInfo;\r
742         swInfo.fMakeSFX = e.GetId() == XRCID("Arc_SFX");\r
743 \r
744         // 保存先を尋ねる。\r
745         wxFileDialog fd(this, swInfo.fMakeSFX ? _("Save as SFX") : _("Save as normal archive"), this->fnArchive.GetPath(), this->fnArchive.GetName() + (swInfo.fMakeSFX ? EXE_EXT : (wxString) wxEmptyString), wxFileSelectorDefaultWildcardStr, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);\r
746         if (fd.ShowModal() == wxID_CANCEL)\r
747         {\r
748                 return;\r
749         }\r
750         swInfo.fnDestinationDirectory = wxFileName::DirName(fd.GetDirectory());\r
751         this->conf.WriteHistory(CONF_HISTORY_PATH, fd.GetDirectory());\r
752 \r
753         wxArrayString files;\r
754         files.Add(fd.GetPath());\r
755 \r
756         ProcessDialog procDlg(this);\r
757         tpi.Command(swInfo.fMakeSFX ? TPI_COMMAND_SFX : TPI_COMMAND_UNSFX, & swInfo, this->fnArchive.GetFullPath(), files);\r
758         this->ErrorCheck(tpi.nErrorCode);\r
759         procDlg.Show(false);\r
760 }\r
761 \r
762 void MainFrame::OnArcExtract(wxCommandEvent& e)\r
763 {\r
764         TPI_SWITCHES swInfo;\r
765         swInfo.pCustomSwitches = NULL;\r
766         swInfo.szPassword = this->szPassword;\r
767 \r
768         // モード取得。通常は0, 実行なら1, ファイルDnDなら2、ディレクトリDnDなら3、クリップボードなら4、コンテキストメニューからなら8。\r
769         int nMode = e.GetInt();\r
770         if (e.GetInt() == 8)\r
771         {\r
772                 nMode = 0;\r
773         }\r
774         // 実行時のみ使用。\r
775         wxFileType * ftFile = NULL;\r
776 \r
777         // 展開ダイアログを作成。DnDまたは実行時は表示しない。\r
778         MakeDialog mkDlg(this, TPI_COMMAND_EXTRACT);\r
779         mkDlg.files    = MakeTargetFileList(this, nMode == 1, nMode == 0);\r
780 \r
781         bool bMakeDir = false;\r
782         if (nMode != 0)\r
783         {\r
784                 // 作業ディレクトリ作成。\r
785                 swInfo.fStoreDirectoryPathes = false;\r
786                 wxString szDestDirBase = nMode == 3 ? this->tree_ctrl->GetItemText(this->tree_ctrl->GetSelection()) : wxT("tpi_tmp");\r
787                 if (szDestDirBase == wxT("-----"))\r
788                 {\r
789                         // 書庫ルートのときは書庫名にしておく。\r
790                         szDestDirBase = this->fnArchive.GetName();\r
791                 }\r
792                 swInfo.fnDestinationDirectory = MakeDirPath(wxFileName::DirName(wxStandardPaths::Get().GetTempDir()), szDestDirBase, true);\r
793                 if (! swInfo.fnDestinationDirectory.IsOk())\r
794                 {\r
795                         wxLogError(_("Unable to make the temporary directory!"));\r
796                         return;\r
797                 }\r
798         }\r
799         else\r
800         {\r
801                 if (mkDlg.ShowModal() == wxID_CANCEL)\r
802                 {\r
803                         return;\r
804                 }\r
805 \r
806                 // 各種設定。\r
807                 swInfo.fStoreDirectoryPathes = ! mkDlg.cbIgnorePath->IsChecked();\r
808                 swInfo.fnDestinationDirectory = wxFileName::DirName(mkDlg.cbDir->GetValue());\r
809                 swInfo.szPassword = mkDlg.tcPassword->GetValue();\r
810                 swInfo.szKeyFile  = mkDlg.tcKeyfile->GetValue();\r
811 \r
812                 // 必要なら書庫名でディレクトリを作成する。\r
813                 bMakeDir = WillMakeDirByArcName(this, & mkDlg);\r
814                 if (bMakeDir)\r
815                 {\r
816                         swInfo.fnDestinationDirectory = MakeDirPath(swInfo.fnDestinationDirectory, this->fnArchive.GetName(), true);\r
817                         if (! swInfo.fnDestinationDirectory.IsOk())\r
818                         {\r
819                                 wxLogError(_("Unable to make the destination directory!"));\r
820                                 return;\r
821                         }\r
822                 }\r
823         }\r
824 \r
825         // 処理を行う。\r
826         {\r
827                 ProcessDialog procDlg(this, mkDlg.files.GetCount(), this->szPassword);\r
828                 tpi.Command(TPI_COMMAND_EXTRACT, & swInfo, this->fnArchive.GetFullPath(), mkDlg.files);\r
829                 this->ErrorCheck(tpi.nErrorCode);\r
830                 procDlg.Show(false);\r
831         }\r
832 \r
833         if (nMode == 0)\r
834         {\r
835                 if (mkDlg.cbOpenAfter->IsChecked())\r
836                 {\r
837                         // 展開先を開く。\r
838                         if (mkDlg.chDirMake->GetSelection() == 2 && ! bMakeDir)\r
839                         {\r
840                                 wxTreeItemId tiArcSub = this->tree_ctrl->GetLastChild(this->tree_ctrl->GetLastChild(this->tree_ctrl->GetRootItem()));\r
841                                 if (tiArcSub.IsOk())\r
842                                 {\r
843                                         swInfo.fnDestinationDirectory.SetFullName(this->tree_ctrl->GetItemText(tiArcSub));\r
844                                 }\r
845                         }\r
846                         ::wxExecute(DIR_APP + QuoteString(swInfo.fnDestinationDirectory.GetFullPath()));\r
847                 }\r
848 \r
849                 if (mkDlg.cbExitAfter->IsChecked())\r
850                 {\r
851                         // 終了。\r
852                         this->Close(true);\r
853                 }\r
854         }\r
855         else\r
856         {\r
857                 if (nMode == 1)\r
858                 {\r
859                         // コマンドを取得。\r
860                         ftFile = wxTheMimeTypesManager->GetFileTypeFromExtension(wxFileName(mkDlg.files[0], wxPATH_DOS).GetExt());\r
861                         if (! ftFile || ftFile->GetOpenCommand(wxEmptyString).IsEmpty())\r
862                         {\r
863                                 // 種類が取得できないときはテキストとみなす。\r
864                                 ftFile = wxTheMimeTypesManager->GetFileTypeFromExtension(this->conf.ReadId(CONF_DEFAULT_EXT, (wxString) wxT("txt")));\r
865                         }\r
866 \r
867                         // コマンドを実行。\r
868                         wxString szTempFile = swInfo.fnDestinationDirectory.GetPathWithSep() + wxFileName(mkDlg.files[0], wxPATH_DOS).GetFullName();\r
869                         bool fSuccess = tpi.nErrorCode == TPI_ERROR_SUCCESS && ftFile != NULL;\r
870                         myProcess * pCallback = new myProcess(szTempFile, swInfo.fnDestinationDirectory.GetPath());\r
871                         if (fSuccess)\r
872                         {\r
873 #ifdef __LINUX__\r
874                                 // Linuxでは引用符で囲む必要がある。\r
875                                 fSuccess = ::wxExecute(ftFile->GetOpenCommand(QuoteString(szTempFile)), wxEXEC_ASYNC, pCallback) > 0;\r
876 #else\r
877                                 fSuccess = ::wxExecute(ftFile->GetOpenCommand(szTempFile), wxEXEC_ASYNC, pCallback) > 0;\r
878 #endif\r
879                         }\r
880                         if (! fSuccess)\r
881                         {\r
882                                 pCallback->OnTerminate(0, 0);\r
883                         }\r
884                 }\r
885                 else\r
886                 {\r
887                         // 展開対象を決定。\r
888                         wxArrayString asFiles;\r
889                         myFileDataObject * objFile = new myFileDataObject();\r
890                         objFile->szTempDir = nMode == 3 ? swInfo.fnDestinationDirectory.GetPath() : swInfo.fnDestinationDirectory.GetFullPath();\r
891                         for (size_t i = 0; i < mkDlg.files.GetCount(); i++)\r
892                         {\r
893                                 wxString szFileName = swInfo.fnDestinationDirectory.GetPathWithSep() + wxFileName(mkDlg.files[i], wxPATH_DOS).GetFullName();\r
894                                 if (nMode == 3)\r
895                                 {\r
896                                         asFiles.Add(szFileName);\r
897                                 }\r
898                                 else\r
899                                 {\r
900                                         // リストに追加。\r
901                                         objFile->AddFile(szFileName);\r
902                                 }\r
903                         }\r
904                         if (nMode == 3)\r
905                         {\r
906                                 objFile->AddFile(objFile->szTempDir);\r
907                         }\r
908 \r
909                         if (nMode == 4)\r
910                         {\r
911                                 wxTheClipboard->SetData(objFile);\r
912                         }\r
913                         else\r
914                         {\r
915                                 // 自身にドロップされると煩雑なので、一時的にドロップを受け付けないようにしておく。\r
916                                 this->SetDropTarget(NULL);\r
917 \r
918                                 // DnD開始。\r
919                                 wxDropSource dropSource(* objFile, this);\r
920                                 wxDragResult drResult = dropSource.DoDragDrop();\r
921                                 if (drResult != wxDragCancel && drResult != wxDragNone && drResult != wxDragMove)\r
922                                 {\r
923 #ifdef __LINUX__\r
924                                         // Linuxではまだ処理が終わっていない(コンテキストメニューが表示されている)ので、とりあえず3秒だけ待つ。\r
925                                         sleep(3);\r
926 #endif\r
927                                 }\r
928                                 this->SetDropTarget(new myFileDropTarget(this));\r
929 \r
930                                 // ディレクトリDnDのときは、先にディレクトリの中のファイルを消しておく。\r
931                                 if (nMode == 3)\r
932                                 {\r
933                                         for (size_t i = 0; i < asFiles.GetCount(); i++)\r
934                                         {\r
935                                                 chmod(asFiles[i].ToUTF8(), 0600);\r
936                                                 ::wxRemoveFile(asFiles[i]);\r
937                                         }\r
938                                 }\r
939 \r
940                                 delete objFile;\r
941                         }\r
942                 }\r
943         }\r
944 }\r
945 \r
946 void MainFrame::OnArcDelete(wxCommandEvent& e)\r
947 {\r
948         // 全ファイル削除は危険ではないかと。\r
949         if (this->list_ctrl->GetSelectedItemCount() == 0)\r
950         {\r
951                 // wxのバグで自動では無効化できないので、実行しようとしたときに無効化する。\r
952                 SetMenuToolState("Arc_Delete", false);\r
953                 return;\r
954         }\r
955 \r
956         if (::AskDlg(_("Are you sure to delete selected files?"), this) == wxNO)\r
957         {\r
958                 return;\r
959         }\r
960 \r
961         // 処理を行う。\r
962         {\r
963                 wxArrayString asFiles = MakeTargetFileList(this);\r
964                 ProcessDialog procDlg(this, asFiles.GetCount(), this->szPassword);\r
965                 TPI_SWITCHES swInfo;\r
966                 swInfo.szPassword = this->szPassword;\r
967                 tpi.Command(TPI_COMMAND_DELETE, & swInfo, this->fnArchive.GetFullPath(), asFiles);\r
968                 this->ErrorCheck(tpi.nErrorCode);\r
969                 procDlg.Show(false);\r
970         }\r
971 \r
972         // 書庫を再読み込みする。\r
973         this->OnArcOpen(e);\r
974 }\r
975 \r
976 void MainFrame::OnArcTest(wxCommandEvent&)\r
977 {\r
978         // 処理を行う。\r
979         wxArrayString asFiles = MakeTargetFileList(this);\r
980         ProcessDialog procDlg(this, asFiles.GetCount(), this->szPassword);\r
981         TPI_SWITCHES swInfo;\r
982         swInfo.szPassword = this->szPassword;\r
983         tpi.Command(TPI_COMMAND_TEST, & swInfo, this->fnArchive.GetFullPath(), asFiles);\r
984         this->ErrorCheck(tpi.nErrorCode);\r
985         procDlg.Show(false);\r
986 }\r
987 \r
988 void MainFrame::OnArcRepair(wxCommandEvent&)\r
989 {\r
990         // 処理を行う。\r
991         wxArrayString asFiles = MakeTargetFileList(this);\r
992         ProcessDialog procDlg(this, asFiles.GetCount(), this->szPassword);\r
993         TPI_SWITCHES swInfo;\r
994         swInfo.szPassword = this->szPassword;\r
995         tpi.Command(TPI_COMMAND_REPAIR, & swInfo, this->fnArchive.GetFullPath(), asFiles);\r
996         this->ErrorCheck(tpi.nErrorCode);\r
997         procDlg.Show(false);    \r
998 }\r
999 \r
1000 void MainFrame::OnExeCopy(wxCommandEvent & e)\r
1001 {\r
1002         if (this->list_ctrl->GetSelectedItemCount() == 0)\r
1003         {\r
1004                 // wxのバグで自動では無効化できないので、実行しようとしたときに無効化する。\r
1005                 this->menubar->Enable(XRCID("Exe_Copy"), false);\r
1006                 return;\r
1007         }\r
1008 \r
1009         if (! wxTheClipboard->Open())\r
1010         {\r
1011                 return;\r
1012         }\r
1013 \r
1014         e.SetInt(4);\r
1015         this->OnArcExtract(e);\r
1016         wxTheClipboard->Close();\r
1017 }\r
1018 \r
1019 void MainFrame::OnViewMode(wxCommandEvent & e)\r
1020 {\r
1021         int n = e.GetId();\r
1022         this->menubar->Check(n, true);\r
1023         this->list_ctrl->SetSingleStyle(wxLC_REPORT, n == XRCID("Exe_View_Details"));\r
1024         this->list_ctrl->SetSingleStyle(wxLC_ICON,   n == XRCID("Exe_View_Icons"));\r
1025         this->list_ctrl->SetSingleStyle(wxLC_LIST,   n == XRCID("Exe_View_List"));\r
1026 }\r
1027 \r
1028 void MainFrame::OnShowToolBar(wxCommandEvent & e)\r
1029 {\r
1030         this->toolbar->Show(e.IsChecked());\r
1031 }\r
1032 \r
1033 void MainFrame::OnShowStatusBar(wxCommandEvent & e)\r
1034 {\r
1035         this->statusbar->Show(e.IsChecked());\r
1036 }\r
1037 \r
1038 void MainFrame::OnSelectAll(wxCommandEvent &)\r
1039 {\r
1040         for (int i = 0; i < this->list_ctrl->GetItemCount(); i++)\r
1041         {\r
1042                 this->list_ctrl->Select(i, true);\r
1043         }\r
1044 }\r
1045 \r
1046 // TreeView\r
1047 \r
1048 void MainFrame::OnTreeChanged(wxTreeEvent& e)\r
1049 {\r
1050         // ツリービューからパスを取得。\r
1051         wxString szNodePath = TreeView_GetItemPath(this->tree_ctrl, e.GetItem());\r
1052         // リストビューを初期化。\r
1053         this->list_ctrl->apShowFile.Clear();\r
1054         this->list_ctrl->DeleteAllItems();\r
1055         g_hIconLL.RemoveAll();\r
1056         g_hIconLS.RemoveAll();\r
1057 \r
1058         // 現在のアイテムの選択状態を無効にしておく。\r
1059         long nSelected = this->list_ctrl->GetFirstSelected();\r
1060         while (nSelected != -1)\r
1061         {\r
1062                 this->list_ctrl->Select(nSelected, false);\r
1063                 nSelected = this->list_ctrl->GetNextSelected(nSelected);\r
1064         }\r
1065 \r
1066         // アイコン設定。\r
1067         this->list_ctrl->SetImageList(& g_hIconLL, wxIMAGE_LIST_NORMAL);\r
1068         this->list_ctrl->SetImageList(& g_hIconLS, wxIMAGE_LIST_SMALL);\r
1069 \r
1070         // 配列と比較し、パスが一致しなければ消す。\r
1071         for (size_t i = 0; i < this->fileinfo.GetCount(); i++)\r
1072         {\r
1073                 // パスを比較。\r
1074                 if (szNodePath == wxT("*") || szNodePath == this->fileinfo[i].fnFileName.GetPath())\r
1075                 {\r
1076                         // 項目がフォルダであるなら無視。\r
1077                         if (this->fileinfo[i].fnFileName.IsDir() || ! TreeView_CheckNewerItem(this->tree_ctrl, this->tree_ctrl->GetLastChild(this->tree_ctrl->GetRootItem()), this->fileinfo[i].fnFileName.GetFullPath(), false))\r
1078                         {\r
1079                                 continue;\r
1080                         }\r
1081 \r
1082                         // フィルタにかからなければ無視。\r
1083                         if (this->fileinfo[i].fnFileName.GetFullName().MakeLower().Find(this->tcFilter->GetValue().MakeLower()) == wxNOT_FOUND)\r
1084                         {\r
1085                                 continue;\r
1086                         }\r
1087 \r
1088                         this->list_ctrl->apShowFile.Add(& this->fileinfo[i]);\r
1089                 }\r
1090         }\r
1091 \r
1092         // ソートして表示。\r
1093         this->list_ctrl->apShowFile.Sort(& ListCtrlCompareProc);\r
1094         this->list_ctrl->SetItemCount(this->list_ctrl->apShowFile.GetCount());\r
1095 }\r
1096 \r
1097 void MainFrame::OnTreeBeginDrag(wxTreeEvent& e)\r
1098 {\r
1099         // TODO : アイテムが子階層を持っていても展開できない。\r
1100         this->tree_ctrl->SelectItem(e.GetItem());\r
1101 \r
1102         wxCommandEvent e1;\r
1103         e1.SetInt(3);\r
1104         this->OnArcExtract(e1);\r
1105 }\r
1106 \r
1107 void MainFrame::OnContextMenu(wxContextMenuEvent& e)\r
1108 {\r
1109         wxPoint p = e.GetPosition();\r
1110         this->list_ctrl->PopupMenu(this->menubar->GetMenu(1), p == wxDefaultPosition ? this->list_ctrl->GetPosition() : this->list_ctrl->ScreenToClient(p));\r
1111 }\r
1112 \r
1113 // ListView\r
1114 \r
1115 void MainFrame::OnListItemSelect(wxListEvent&)\r
1116 {\r
1117         // ファイルに対する動作の設定。但し、選択解除時はwxのバグで呼び出されない。\r
1118         bool fEnable = this->list_ctrl->GetSelectedItemCount() > 0;\r
1119         SetMenuToolState("Arc_Delete", fEnable && (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_DELETE) == TPI_COMMAND_DELETE && this->aiArchive.fiInfo.fArchive);\r
1120         this->menubar->Enable(XRCID("Exe_Copy"), fEnable);\r
1121 }\r
1122 \r
1123 void MainFrame::OnListItemDClick(wxListEvent&)\r
1124 {\r
1125         wxCommandEvent e;\r
1126         e.SetInt(1);\r
1127         this->OnArcExtract(e);\r
1128 }\r
1129 \r
1130 void MainFrame::OnListBeginDrag(wxListEvent&)\r
1131 {\r
1132         if (this->list_ctrl->GetSelectedItemCount() == 0)\r
1133         {\r
1134                 // アイテムを選択せずドラッグしようとした場合。\r
1135                 return;\r
1136         }\r
1137 \r
1138         wxCommandEvent e;\r
1139         e.SetInt(2);\r
1140         this->OnArcExtract(e);\r
1141 }\r
1142 \r
1143 // Filter\r
1144 \r
1145 void MainFrame::OnFilter(wxCommandEvent&)\r
1146 {\r
1147         wxTreeEvent e;\r
1148         e.SetItem(this->tree_ctrl->GetSelection());\r
1149         this->OnTreeChanged(e);\r
1150 }\r
1151 \r
1152 // イベントハンドラ以外。\r
1153 \r
1154 bool MainFrame::LoadTPI(const wxString & szFileName, wxULongLong_t * llFileCount)\r
1155 {\r
1156         // 書庫を開いていれば閉じておく。\r
1157         wxCommandEvent e;\r
1158         this->OnArcClose(e);\r
1159 \r
1160         // TPIを読み込み。\r
1161         wxDir fs(L_DIR_B_LIB);\r
1162         wxString szTPIName;\r
1163         if (fs.GetFirst(& szTPIName, wxT("*" TPI_EXT)))\r
1164         {\r
1165                 do\r
1166                 {\r
1167                         // 初期化と対応確認。\r
1168                         if (! tpi.InitLibrary(L_DIR_B_LIB + szTPIName, szFileName, TPICallbackProc) || ! tpi.OpenArchive(szFileName, llFileCount))\r
1169                         {\r
1170                                 tpi.FreeLibrary();\r
1171                                 * llFileCount = 0;\r
1172                                 continue;\r
1173                         }\r
1174                         return true;\r
1175                 }\r
1176                 while (fs.GetNext(& szTPIName));\r
1177         }\r
1178         return false;\r
1179 }\r
1180 \r
1181 int MainFrame::ErrorCheck(int nErrorCode, const wxString & szAPIName)\r
1182 {\r
1183         switch (nErrorCode)\r
1184         {\r
1185         case TPI_ERROR_SUCCESS:\r
1186         case TPI_ERROR_S_ENDOFDATA:\r
1187         case TPI_CALLBACK_CONTINUE:\r
1188                 break;\r
1189         case TPI_ERROR_D_UNSUPPORTED:\r
1190                 wxLogError(_("Sorry, this function is not supported yet."));\r
1191                 break;\r
1192         case TPI_ERROR_D_SKIPPED:\r
1193         case TPI_CALLBACK_CANCEL:\r
1194                 break;\r
1195         default:\r
1196                 wxLogError(_("Error: %s()!\nError code: %d"), szAPIName.c_str(), nErrorCode);\r
1197         }\r
1198         return nErrorCode;\r
1199 }\r