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()\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)\nTPI: %s(%s)\nAccess: %s\nModify: %s\nCreate: %s\nComment:\n%s"),\r
528                         this->fnArchive.GetFullName().c_str(), this->aiArchive.fiInfo.szTypeName.c_str(),\r
529                         this->aiArchive.fiInfo.szTPIName.c_str(), this->aiArchive.fiInfo.szEngineName.c_str(),\r
530                         this->aiArchive.tmAccess.Format(_("%Y/%m/%d %H:%M:%S")).c_str(),\r
531                         this->aiArchive.tmModify.Format(_("%Y/%m/%d %H:%M:%S")).c_str(),\r
532                         this->aiArchive.tmCreate.Format(_("%Y/%m/%d %H:%M:%S")).c_str(),\r
533                         this->aiArchive.szComment.c_str()\r
534                 )\r
535         );\r
536 \r
537         // ツールバー・メニューバー設定。ファイル選択時しか動作しない削除などは別に設定。\r
538         SetMenuToolState("Arc_Close",   true);\r
539         SetMenuToolState("Arc_Add",     (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_ADD)   == TPI_COMMAND_ADD   && this->aiArchive.fiInfo.fArchive);\r
540         SetMenuToolState("Arc_SFX",     (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_SFX)    == TPI_COMMAND_SFX   && ! this->aiArchive.fSFX);\r
541         SetMenuToolState("Arc_UnSFX",   (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_UNSFX)  == TPI_COMMAND_UNSFX && this->aiArchive.fSFX);\r
542         SetMenuToolState("Arc_Extract", (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_EXTRACT)== TPI_COMMAND_EXTRACT);\r
543         SetMenuToolState("Arc_Test",    (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_TEST)   == TPI_COMMAND_TEST);\r
544         SetMenuToolState("Arc_Repair",  (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_REPAIR) == TPI_COMMAND_REPAIR);\r
545         this->menubar->Enable(XRCID("Arc_Clone"), true);\r
546 \r
547         procDlg.Show(false);\r
548         this->Raise();\r
549 }\r
550 \r
551 void MainFrame::OnArcClose(wxCommandEvent& e)\r
552 {\r
553         // ツリービュー・リストビュー設定。\r
554         this->tree_ctrl->DeleteAllItems();\r
555         this->list_ctrl->DeleteAllItems();\r
556         this->list_ctrl->apShowFile.Clear();\r
557 \r
558         // ツールバー・メニューバー設定。\r
559         SetMenuToolState("Arc_Close",   false);\r
560         SetMenuToolState("Arc_Add",     false);\r
561         SetMenuToolState("Arc_SFX",     false);\r
562         SetMenuToolState("Arc_UnSFX",   false);\r
563         SetMenuToolState("Arc_Extract", false);\r
564         SetMenuToolState("Arc_Delete",  false);\r
565         SetMenuToolState("Arc_Test",    false);\r
566         SetMenuToolState("Arc_Repair",  false);\r
567         this->menubar->Enable(XRCID("Arc_Clone"), false);\r
568 \r
569         for (int i = 0; i < this->statusbar->GetFieldsCount(); i++)\r
570         {\r
571                 this->statusbar->SetStatusText(wxEmptyString, i);\r
572         }\r
573         this->statusbar->SetToolTip(wxEmptyString);\r
574         this->fileinfo.Clear();\r
575         this->aiArchive.szComment.Empty();\r
576         this->aiArchive.fnArchive.Clear();\r
577         this->aiArchive.fiInfo.szTypeName.Empty();\r
578         this->aiArchive.fiInfo.szSuffix.Empty();\r
579         this->aiArchive.fiInfo.szEngineName.Empty();\r
580         this->aiArchive.fiInfo.szTPIName.Empty();\r
581 \r
582         g_hIconT.RemoveAll();\r
583         g_hIconLL.RemoveAll();\r
584         g_hIconLS.RemoveAll();\r
585 \r
586         // DnDで書庫を開くときは既に読み込まれているTPIを用いるので、解放してはいけない。\r
587         if (e.GetExtraLong() == 0)\r
588         {\r
589                 tpi.FreeLibrary();\r
590         }\r
591 }\r
592 \r
593 void MainFrame::OnArcClone(wxCommandEvent&)\r
594 {\r
595         // 保存先を尋ねる。\r
596         wxFileDialog fd(this, _("Clone archive"), this->fnArchive.GetPath(), this->fnArchive.GetFullName(), wxFileSelectorDefaultWildcardStr, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);\r
597         if (fd.ShowModal() == wxID_CANCEL)\r
598         {\r
599                 return;\r
600         }\r
601         this->conf.WriteHistory(CONF_HISTORY_PATH, fd.GetDirectory());\r
602 \r
603         // コピー。\r
604         ::wxCopyFile(this->fnArchive.GetFullPath(), fd.GetPath());\r
605         wxFileName fn(fd.GetPath());\r
606         wxDateTime dtAccess, dtModify, dtCreate;\r
607         this->fnArchive.GetTimes(& dtAccess, & dtModify, & dtCreate);\r
608         fn.SetTimes(& dtAccess, & dtModify, & dtCreate);\r
609 }\r
610 \r
611 void MainFrame::OnArcAdd(wxCommandEvent& e)\r
612 {\r
613         // 作成ダイアログを設定。\r
614         MakeDialog mkDlg;\r
615         mkDlg.SetParent(this);\r
616         mkDlg.uCommand = TPI_COMMAND_ADD;\r
617 \r
618         TPI_SWITCHES swInfo;\r
619         swInfo.pCustomSwitches       = NULL;\r
620 \r
621         if (e.GetClientData() == NULL)\r
622         {\r
623                 if (::wxGetKeyState(WXK_SHIFT))\r
624                 {\r
625                         // 処理対象のフォルダを選択。\r
626                         wxDirDialog dd(this, _("Choose dir to add"), this->conf.ReadHistory(CONF_HISTORY_PATH, 0), wxDD_DIR_MUST_EXIST);\r
627                         if (dd.ShowModal() == wxID_CANCEL)\r
628                         {\r
629                                 return;\r
630                         }\r
631                         swInfo.fnDestinationDirectory = wxFileName(dd.GetPath());\r
632                         this->conf.WriteHistory(CONF_HISTORY_PATH, swInfo.fnDestinationDirectory.GetPath());\r
633                         mkDlg.files.Add(swInfo.fnDestinationDirectory.GetFullName());\r
634                 }\r
635                 else\r
636                 {\r
637                         // 処理対象のファイルを選択。\r
638                         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
639                         if (fd.ShowModal() == wxID_CANCEL)\r
640                         {\r
641                                 return;\r
642                         }\r
643                         fd.GetFilenames(mkDlg.files);\r
644                         swInfo.fnDestinationDirectory = wxFileName::DirName(fd.GetDirectory());\r
645                         this->conf.WriteHistory(CONF_HISTORY_PATH, fd.GetDirectory());\r
646                 }\r
647         }\r
648         else\r
649         {\r
650                 mkDlg.files = * (wxArrayString *) e.GetClientData();\r
651                 swInfo.fnDestinationDirectory = wxFileName::DirName(wxFileName(mkDlg.files[0]).GetPath());\r
652                 // 相対パスに変換。\r
653                 for (size_t n = 0; n < mkDlg.files.GetCount(); n++)\r
654                 {\r
655                         wxFileName fn(mkDlg.files[n]);\r
656                         fn.MakeRelativeTo(swInfo.fnDestinationDirectory.GetPath());\r
657                         mkDlg.files[n] = fn.GetFullPath();\r
658                 }\r
659         }\r
660 \r
661         // ダイアログを表示。\r
662         if (mkDlg.ShowModal() == wxID_CANCEL)\r
663         {\r
664                 return;\r
665         }\r
666 \r
667         // 各種設定。\r
668         swInfo.fMakeSFX              = false;\r
669         swInfo.fStoreDirectoryPathes = ! mkDlg.cbIgnorePath->IsChecked();\r
670         swInfo.fSolid               = mkDlg.cbSolid->IsChecked();\r
671         swInfo.fMMOptimize          = mkDlg.cbMMOptimize->IsChecked();\r
672         swInfo.fEncryptHeader       = mkDlg.cbEncryptHeader->IsChecked();\r
673         swInfo.nCompressLevel       = mkDlg.scLevel->GetValue();\r
674         swInfo.nRecoveryRecord      = mkDlg.scRR->GetValue();\r
675         swInfo.szPassword           = mkDlg.tcPassword->GetValue();\r
676         swInfo.szKeyFile            = mkDlg.tcKeyfile->GetValue();\r
677         swInfo.szComment            = mkDlg.tcComment->GetValue();\r
678 \r
679         // 処理を行う。\r
680         {\r
681                 ProcessDialog procDlg;\r
682                 procDlg.fnArchive  = & this->fnArchive;\r
683                 procDlg.nFileCount = mkDlg.files.GetCount();\r
684                 procDlg.Show(true);\r
685 \r
686                 tpi.Command(TPI_COMMAND_ADD, & swInfo, this->fnArchive.GetFullPath(), mkDlg.files);\r
687                 this->ErrorCheck(tpi.nErrorCode);\r
688                 procDlg.Show(false);\r
689         }\r
690 \r
691         if (mkDlg.cbOpenAfter->IsChecked())\r
692         {\r
693                 // 作成先を開く。\r
694                 ::wxExecute(DIR_APP + QuoteString(swInfo.fnDestinationDirectory.GetFullPath()));\r
695         }\r
696 \r
697         if (mkDlg.cbExitAfter->IsChecked())\r
698         {\r
699                 // 終了。\r
700                 this->Close(true);\r
701         }\r
702 \r
703         // 終了しない場合は書庫を再読み込み。\r
704         this->OnArcOpen(e);\r
705 }\r
706 \r
707 void MainFrame::OnArcConvert(wxCommandEvent& e)\r
708 {\r
709         TPI_SWITCHES swInfo;\r
710         swInfo.fMakeSFX = e.GetId() == XRCID("Arc_SFX");\r
711 \r
712         // 保存先を尋ねる。\r
713         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
714         if (fd.ShowModal() == wxID_CANCEL)\r
715         {\r
716                 return;\r
717         }\r
718         swInfo.fnDestinationDirectory = wxFileName::DirName(fd.GetDirectory());\r
719         this->conf.WriteHistory(CONF_HISTORY_PATH, fd.GetDirectory());\r
720 \r
721         wxArrayString files;\r
722         files.Add(fd.GetPath());\r
723 \r
724         ProcessDialog procDlg;\r
725         procDlg.Show(true);\r
726         tpi.Command(swInfo.fMakeSFX ? TPI_COMMAND_SFX : TPI_COMMAND_UNSFX, & swInfo, this->fnArchive.GetFullPath(), files);\r
727         this->ErrorCheck(tpi.nErrorCode);\r
728         procDlg.Show(false);\r
729 }\r
730 \r
731 void MainFrame::OnArcExtract(wxCommandEvent& e)\r
732 {\r
733         TPI_SWITCHES swInfo;\r
734         swInfo.pCustomSwitches = NULL;\r
735 \r
736         // モード取得。通常は0, 実行なら1, ファイルDnDなら2、ディレクトリDnDなら3、クリップボードなら4、コンテキストメニューからなら8。\r
737         int nMode = e.GetInt();\r
738         if (e.GetInt() == 8)\r
739         {\r
740                 nMode = 0;\r
741         }\r
742         // 実行時のみ使用。\r
743         wxFileType * ftFile = NULL;\r
744 \r
745         // 展開ダイアログを作成。DnDまたは実行時は表示しない。\r
746         MakeDialog mkDlg;\r
747         mkDlg.SetParent(this);\r
748         mkDlg.uCommand = TPI_COMMAND_EXTRACT;\r
749         mkDlg.files    = MakeTargetFileList(this, nMode == 1, nMode == 0);\r
750 \r
751         bool bMakeDir = false;\r
752         if (nMode != 0)\r
753         {\r
754                 // 作業ディレクトリ作成。\r
755                 swInfo.fStoreDirectoryPathes = false;\r
756                 wxString szDestDirBase = nMode == 3 ? this->tree_ctrl->GetItemText(this->tree_ctrl->GetSelection()) : wxT("tpi_tmp");\r
757                 wxStandardPaths p;\r
758                 if (szDestDirBase == wxT("-----"))\r
759                 {\r
760                         // 書庫ルートのときは書庫名にしておく。\r
761                         szDestDirBase = this->fnArchive.GetName();\r
762                 }\r
763                 swInfo.fnDestinationDirectory = MakeDirPath(wxFileName::DirName(p.GetTempDir()), szDestDirBase, true);\r
764                 if (! swInfo.fnDestinationDirectory.IsOk())\r
765                 {\r
766                         wxLogError(_("Unable to make the temporary directory!"));\r
767                         return;\r
768                 }\r
769         }\r
770         else\r
771         {\r
772                 if (mkDlg.ShowModal() == wxID_CANCEL)\r
773                 {\r
774                         return;\r
775                 }\r
776 \r
777                 // 各種設定。\r
778                 swInfo.fStoreDirectoryPathes = ! mkDlg.cbIgnorePath->IsChecked();\r
779                 swInfo.fnDestinationDirectory = wxFileName::DirName(mkDlg.cbDir->GetValue());\r
780                 swInfo.szPassword = mkDlg.tcPassword->GetValue();\r
781                 swInfo.szKeyFile  = mkDlg.tcKeyfile->GetValue();\r
782 \r
783                 // 必要なら書庫名でディレクトリを作成する。\r
784                 bMakeDir = WillMakeDirByArcName(this, & mkDlg);\r
785                 if (bMakeDir)\r
786                 {\r
787                         swInfo.fnDestinationDirectory = MakeDirPath(swInfo.fnDestinationDirectory, this->fnArchive.GetName(), true);\r
788                         if (! swInfo.fnDestinationDirectory.IsOk())\r
789                         {\r
790                                 wxLogError(_("Unable to make the destination directory!"));\r
791                                 return;\r
792                         }\r
793                 }\r
794         }\r
795 \r
796         // 処理を行う。\r
797         {\r
798                 ProcessDialog procDlg;\r
799                 procDlg.fnArchive  = & this->fnArchive;\r
800                 procDlg.nFileCount = mkDlg.files.GetCount();\r
801                 procDlg.Show(true);\r
802 \r
803                 tpi.Command(TPI_COMMAND_EXTRACT, & swInfo, this->fnArchive.GetFullPath(), mkDlg.files);\r
804                 this->ErrorCheck(tpi.nErrorCode);\r
805                 procDlg.Show(false);\r
806         }\r
807 \r
808         if (nMode == 0)\r
809         {\r
810                 if (mkDlg.cbOpenAfter->IsChecked())\r
811                 {\r
812                         // 展開先を開く。\r
813                         if (mkDlg.chDirMake->GetSelection() == 2 && ! bMakeDir)\r
814                         {\r
815                                 wxTreeItemId tiArcSub = this->tree_ctrl->GetLastChild(this->tree_ctrl->GetLastChild(this->tree_ctrl->GetRootItem()));\r
816                                 if (tiArcSub.IsOk())\r
817                                 {\r
818                                         swInfo.fnDestinationDirectory.SetFullName(this->tree_ctrl->GetItemText(tiArcSub));\r
819                                 }\r
820                         }\r
821                         ::wxExecute(DIR_APP + QuoteString(swInfo.fnDestinationDirectory.GetFullPath()));\r
822                 }\r
823 \r
824                 if (mkDlg.cbExitAfter->IsChecked())\r
825                 {\r
826                         // 終了。\r
827                         this->Close(true);\r
828                 }\r
829         }\r
830         else\r
831         {\r
832                 if (nMode == 1)\r
833                 {\r
834                         // コマンドを取得。\r
835                         ftFile = wxTheMimeTypesManager->GetFileTypeFromExtension(wxFileName(mkDlg.files[0], wxPATH_DOS).GetExt());\r
836                         if (! ftFile || ftFile->GetOpenCommand(wxEmptyString).IsEmpty())\r
837                         {\r
838                                 // 種類が取得できないときはテキストとみなす。\r
839                                 ftFile = wxTheMimeTypesManager->GetFileTypeFromExtension(this->conf.ReadId(CONF_DEFAULT_EXT, (wxString) wxT("txt")));\r
840                         }\r
841 \r
842                         // コマンドを実行。\r
843                         wxString szTempFile = swInfo.fnDestinationDirectory.GetPathWithSep() + wxFileName(mkDlg.files[0], wxPATH_DOS).GetFullName();\r
844                         bool fSuccess = tpi.nErrorCode == TPI_ERROR_SUCCESS && ftFile != NULL;\r
845                         myProcess * pCallback = new myProcess(szTempFile, swInfo.fnDestinationDirectory.GetPath());\r
846                         if (fSuccess)\r
847                         {\r
848 #ifdef __LINUX__\r
849                                 // Linuxでは引用符で囲む必要がある。\r
850                                 fSuccess = ::wxExecute(ftFile->GetOpenCommand(QuoteString(szTempFile)), wxEXEC_ASYNC, pCallback) > 0;\r
851 #else\r
852                                 fSuccess = ::wxExecute(ftFile->GetOpenCommand(szTempFile), wxEXEC_ASYNC, pCallback) > 0;\r
853 #endif\r
854                         }\r
855                         if (! fSuccess)\r
856                         {\r
857                                 pCallback->OnTerminate(0, 0);\r
858                         }\r
859                 }\r
860                 else\r
861                 {\r
862                         // 展開対象を決定。\r
863                         wxArrayString asFiles;\r
864                         myFileDataObject * objFile = new myFileDataObject();\r
865                         objFile->szTempDir = nMode == 3 ? swInfo.fnDestinationDirectory.GetPath() : swInfo.fnDestinationDirectory.GetFullPath();\r
866                         for (size_t i = 0; i < mkDlg.files.GetCount(); i++)\r
867                         {\r
868                                 wxString szFileName = swInfo.fnDestinationDirectory.GetPathWithSep() + wxFileName(mkDlg.files[i], wxPATH_DOS).GetFullName();\r
869                                 if (nMode == 3)\r
870                                 {\r
871                                         asFiles.Add(szFileName);\r
872                                 }\r
873                                 else\r
874                                 {\r
875                                         // リストに追加。\r
876                                         objFile->AddFile(szFileName);\r
877                                 }\r
878                         }\r
879                         if (nMode == 3)\r
880                         {\r
881                                 objFile->AddFile(objFile->szTempDir);\r
882                         }\r
883 \r
884                         if (nMode == 4)\r
885                         {\r
886                                 wxTheClipboard->SetData(objFile);\r
887                         }\r
888                         else\r
889                         {\r
890                                 // 自身にドロップされると煩雑なので、一時的にドロップを受け付けないようにしておく。\r
891                                 this->SetDropTarget(NULL);\r
892 \r
893                                 // DnD開始。\r
894                                 wxDropSource dropSource(* objFile, this);\r
895                                 wxDragResult drResult = dropSource.DoDragDrop();\r
896                                 if (drResult != wxDragCancel && drResult != wxDragNone && drResult != wxDragMove)\r
897                                 {\r
898 #ifdef __LINUX__\r
899                                         // Linuxではまだ処理が終わっていない(コンテキストメニューが表示されている)ので、とりあえず3秒だけ待つ。\r
900                                         sleep(3);\r
901 #endif\r
902                                 }\r
903                                 this->SetDropTarget(new myFileDropTarget(this));\r
904 \r
905                                 // ディレクトリDnDのときは、先にディレクトリの中のファイルを消しておく。\r
906                                 if (nMode == 3)\r
907                                 {\r
908                                         for (size_t i = 0; i < asFiles.GetCount(); i++)\r
909                                         {\r
910                                                 chmod(asFiles[i].ToUTF8(), 0600);\r
911                                                 ::wxRemoveFile(asFiles[i]);\r
912                                         }\r
913                                 }\r
914 \r
915                                 delete objFile;\r
916                         }\r
917                 }\r
918         }\r
919 }\r
920 \r
921 void MainFrame::OnArcDelete(wxCommandEvent& e)\r
922 {\r
923         // 全ファイル削除は危険ではないかと。\r
924         if (this->list_ctrl->GetSelectedItemCount() == 0)\r
925         {\r
926                 // wxのバグで自動では無効化できないので、実行しようとしたときに無効化する。\r
927                 SetMenuToolState("Arc_Delete", false);\r
928                 return;\r
929         }\r
930 \r
931         if (::AskDlg(_("Are you sure to delete selected files?"), this) == wxNO)\r
932         {\r
933                 return;\r
934         }\r
935 \r
936         // 処理を行う。\r
937         {\r
938                 wxArrayString asFiles = MakeTargetFileList(this);\r
939                 ProcessDialog procDlg;\r
940                 procDlg.fnArchive  = & this->fnArchive;\r
941                 procDlg.nFileCount = asFiles.GetCount();\r
942                 procDlg.Show(true);\r
943 \r
944                 TPI_SWITCHES swInfo;\r
945                 tpi.Command(TPI_COMMAND_DELETE, & swInfo, this->fnArchive.GetFullPath(), asFiles);\r
946                 this->ErrorCheck(tpi.nErrorCode);\r
947                 procDlg.Show(false);\r
948         }\r
949 \r
950         // 書庫を再読み込みする。\r
951         this->OnArcOpen(e);\r
952 }\r
953 \r
954 void MainFrame::OnArcTest(wxCommandEvent&)\r
955 {\r
956         // 処理を行う。\r
957         wxArrayString asFiles = MakeTargetFileList(this);\r
958         ProcessDialog procDlg;\r
959         procDlg.fnArchive  = & this->fnArchive;\r
960         procDlg.nFileCount = asFiles.GetCount();\r
961         procDlg.Show(true);\r
962 \r
963         TPI_SWITCHES swInfo;\r
964         bool bIsCorrect = tpi.Command(TPI_COMMAND_TEST, & swInfo, this->fnArchive.GetFullPath(), asFiles);\r
965         procDlg.Show(false);\r
966 \r
967         if (bIsCorrect)\r
968         {\r
969                 wxLogMessage(_("This is a correct archive."));\r
970         }\r
971         else\r
972         {\r
973                 this->ErrorCheck(tpi.nErrorCode);\r
974         }\r
975 }\r
976 \r
977 void MainFrame::OnArcRepair(wxCommandEvent&)\r
978 {\r
979         // 処理を行う。\r
980         wxArrayString asFiles = MakeTargetFileList(this);\r
981         ProcessDialog procDlg;\r
982         procDlg.fnArchive  = & this->fnArchive;\r
983         procDlg.nFileCount = asFiles.GetCount();\r
984         procDlg.Show(true);\r
985 \r
986         TPI_SWITCHES swInfo;\r
987         tpi.Command(TPI_COMMAND_REPAIR, & swInfo, this->fnArchive.GetFullPath(), asFiles);\r
988         this->ErrorCheck(tpi.nErrorCode);\r
989         procDlg.Show(false);    \r
990 }\r
991 \r
992 void MainFrame::OnExeCopy(wxCommandEvent & e)\r
993 {\r
994         if (this->list_ctrl->GetSelectedItemCount() == 0)\r
995         {\r
996                 // wxのバグで自動では無効化できないので、実行しようとしたときに無効化する。\r
997                 this->menubar->Enable(XRCID("Exe_Copy"), false);\r
998                 return;\r
999         }\r
1000 \r
1001         if (! wxTheClipboard->Open())\r
1002         {\r
1003                 return;\r
1004         }\r
1005 \r
1006         e.SetInt(4);\r
1007         this->OnArcExtract(e);\r
1008         wxTheClipboard->Close();\r
1009 }\r
1010 \r
1011 void MainFrame::OnViewMode(wxCommandEvent & e)\r
1012 {\r
1013         int n = e.GetId();\r
1014         this->menubar->Check(n, true);\r
1015         this->list_ctrl->SetSingleStyle(wxLC_REPORT, n == XRCID("Exe_View_Details"));\r
1016         this->list_ctrl->SetSingleStyle(wxLC_ICON,   n == XRCID("Exe_View_Icons"));\r
1017         this->list_ctrl->SetSingleStyle(wxLC_LIST,   n == XRCID("Exe_View_List"));\r
1018 }\r
1019 \r
1020 void MainFrame::OnShowToolBar(wxCommandEvent & e)\r
1021 {\r
1022         this->toolbar->Show(e.IsChecked());\r
1023 }\r
1024 \r
1025 void MainFrame::OnShowStatusBar(wxCommandEvent & e)\r
1026 {\r
1027         this->statusbar->Show(e.IsChecked());\r
1028 }\r
1029 \r
1030 void MainFrame::OnSelectAll(wxCommandEvent &)\r
1031 {\r
1032         for (int i = 0; i < this->list_ctrl->GetItemCount(); i++)\r
1033         {\r
1034                 this->list_ctrl->Select(i, true);\r
1035         }\r
1036 }\r
1037 \r
1038 // TreeView\r
1039 \r
1040 void MainFrame::OnTreeChanged(wxTreeEvent& e)\r
1041 {\r
1042         // ツリービューからパスを取得。\r
1043         wxString szNodePath = TreeView_GetItemPath(this->tree_ctrl, e.GetItem());\r
1044         // リストビューを初期化。\r
1045         this->list_ctrl->apShowFile.Clear();\r
1046         this->list_ctrl->DeleteAllItems();\r
1047         g_hIconLL.RemoveAll();\r
1048         g_hIconLS.RemoveAll();\r
1049 \r
1050         // 現在のアイテムの選択状態を無効にしておく。\r
1051         long nSelected = this->list_ctrl->GetFirstSelected();\r
1052         while (nSelected != -1)\r
1053         {\r
1054                 this->list_ctrl->Select(nSelected, false);\r
1055                 nSelected = this->list_ctrl->GetNextSelected(nSelected);\r
1056         }\r
1057 \r
1058         // アイコン設定。\r
1059         this->list_ctrl->SetImageList(& g_hIconLL, wxIMAGE_LIST_NORMAL);\r
1060         this->list_ctrl->SetImageList(& g_hIconLS, wxIMAGE_LIST_SMALL);\r
1061 \r
1062         // 配列と比較し、パスが一致しなければ消す。\r
1063         for (size_t i = 0; i < this->fileinfo.GetCount(); i++)\r
1064         {\r
1065                 // パスを比較。\r
1066                 if (szNodePath == wxT("*") || szNodePath == this->fileinfo[i].fnFileName.GetPath())\r
1067                 {\r
1068                         // 項目がフォルダであるなら無視。\r
1069                         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
1070                         {\r
1071                                 continue;\r
1072                         }\r
1073 \r
1074                         // フィルタにかからなければ無視。\r
1075                         if (this->fileinfo[i].fnFileName.GetFullName().MakeLower().Find(this->tcFilter->GetValue().MakeLower()) == wxNOT_FOUND)\r
1076                         {\r
1077                                 continue;\r
1078                         }\r
1079 \r
1080                         this->list_ctrl->apShowFile.Add(& this->fileinfo[i]);\r
1081                 }\r
1082         }\r
1083 \r
1084         // ソートして表示。\r
1085         this->list_ctrl->apShowFile.Sort(& ListCtrlCompareProc);\r
1086         this->list_ctrl->SetItemCount(this->list_ctrl->apShowFile.GetCount());\r
1087 }\r
1088 \r
1089 void MainFrame::OnTreeBeginDrag(wxTreeEvent& e)\r
1090 {\r
1091         // TODO : アイテムが子階層を持っていても展開できない。\r
1092         this->tree_ctrl->SelectItem(e.GetItem());\r
1093 \r
1094         wxCommandEvent e1;\r
1095         e1.SetInt(3);\r
1096         this->OnArcExtract(e1);\r
1097 }\r
1098 \r
1099 void MainFrame::OnContextMenu(wxContextMenuEvent& e)\r
1100 {\r
1101         wxPoint p = e.GetPosition();\r
1102         this->list_ctrl->PopupMenu(this->menubar->GetMenu(1), p == wxDefaultPosition ? this->list_ctrl->GetPosition() : this->list_ctrl->ScreenToClient(p));\r
1103 }\r
1104 \r
1105 // ListView\r
1106 \r
1107 void MainFrame::OnListItemSelect(wxListEvent&)\r
1108 {\r
1109         // ファイルに対する動作の設定。但し、選択解除時はwxのバグで呼び出されない。\r
1110         bool fEnable = this->list_ctrl->GetSelectedItemCount() > 0;\r
1111         SetMenuToolState("Arc_Delete", fEnable && (this->aiArchive.fiInfo.eSupportedCommand & TPI_COMMAND_DELETE) == TPI_COMMAND_DELETE && this->aiArchive.fiInfo.fArchive);\r
1112         this->menubar->Enable(XRCID("Exe_Copy"), fEnable);\r
1113 }\r
1114 \r
1115 void MainFrame::OnListItemDClick(wxListEvent&)\r
1116 {\r
1117         wxCommandEvent e;\r
1118         e.SetInt(1);\r
1119         this->OnArcExtract(e);\r
1120 }\r
1121 \r
1122 void MainFrame::OnListBeginDrag(wxListEvent&)\r
1123 {\r
1124         if (this->list_ctrl->GetSelectedItemCount() == 0)\r
1125         {\r
1126                 // アイテムを選択せずドラッグしようとした場合。\r
1127                 return;\r
1128         }\r
1129 \r
1130         wxCommandEvent e;\r
1131         e.SetInt(2);\r
1132         this->OnArcExtract(e);\r
1133 }\r
1134 \r
1135 // Filter\r
1136 \r
1137 void MainFrame::OnFilter(wxCommandEvent&)\r
1138 {\r
1139         wxTreeEvent e;\r
1140         e.SetItem(this->tree_ctrl->GetSelection());\r
1141         this->OnTreeChanged(e);\r
1142 }\r
1143 \r
1144 // イベントハンドラ以外。\r
1145 \r
1146 bool MainFrame::LoadTPI(const wxString & szFileName, wxULongLong_t * llFileCount)\r
1147 {\r
1148         // 書庫を開いていれば閉じておく。\r
1149         wxCommandEvent e;\r
1150         this->OnArcClose(e);\r
1151 \r
1152         // TPIを読み込み。\r
1153         wxDir fs(L_DIR_B_LIB);\r
1154         wxString szTPIName;\r
1155         if (fs.GetFirst(& szTPIName, wxT("*" TPI_EXT)))\r
1156         {\r
1157                 do\r
1158                 {\r
1159                         // 初期化。\r
1160                         if (! tpi.InitLibrary(L_DIR_B_LIB + szTPIName, szFileName, TPICallbackProc))\r
1161                         {\r
1162                                 tpi.FreeLibrary();\r
1163                                 continue;\r
1164                         }\r
1165 \r
1166                         // 対応確認。\r
1167                         if (! tpi.OpenArchive(szFileName, llFileCount))\r
1168                         {\r
1169                                 tpi.FreeLibrary();\r
1170                                 * llFileCount = 0;\r
1171                                 continue;\r
1172                         }\r
1173                         return true;\r
1174                 }\r
1175                 while (fs.GetNext(& szTPIName));\r
1176         }\r
1177         return false;\r
1178 }\r
1179 \r
1180 int MainFrame::ErrorCheck(int nErrorCode, const wxString & szAPIName)\r
1181 {\r
1182         switch (nErrorCode)\r
1183         {\r
1184         case TPI_ERROR_SUCCESS:\r
1185         case TPI_ERROR_S_ENDOFDATA:\r
1186         case TPI_CALLBACK_CONTINUE:\r
1187                 break;\r
1188         case TPI_ERROR_D_UNSUPPORTED:\r
1189                 wxLogError(_("Sorry, this function is not supported yet."));\r
1190                 break;\r
1191         case TPI_ERROR_D_SKIPPED:\r
1192         case TPI_CALLBACK_CANCEL:\r
1193                 wxLogError(_("This operation is canceled by the user."));\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