OSDN Git Service

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